refactor: Ran pyupgrade on openedx/core/djangoapps/enrollments (#26912)
Co-authored-by: Muhammad Soban Javed <58461728+iamsobanjaved@users.noreply.github.com> Co-authored-by: Muhammad Soban Javed <58461728+iamsobanjaved@users.noreply.github.com>
This commit is contained in:
@@ -257,7 +257,7 @@ def update_enrollment(
|
||||
}
|
||||
|
||||
"""
|
||||
log.info(u'Starting Update Enrollment process for user {user} in course {course} to mode {mode}'.format(
|
||||
log.info('Starting Update Enrollment process for user {user} in course {course} to mode {mode}'.format(
|
||||
user=username,
|
||||
course=course_id,
|
||||
mode=mode,
|
||||
@@ -266,13 +266,13 @@ def update_enrollment(
|
||||
validate_course_mode(course_id, mode, is_active=is_active, include_expired=include_expired)
|
||||
enrollment = _data_api().update_course_enrollment(username, course_id, mode=mode, is_active=is_active)
|
||||
if enrollment is None: # lint-amnesty, pylint: disable=no-else-raise
|
||||
msg = u"Course Enrollment not found for user {user} in course {course}".format(user=username, course=course_id)
|
||||
msg = f"Course Enrollment not found for user {username} in course {course_id}"
|
||||
log.warning(msg)
|
||||
raise errors.EnrollmentNotFoundError(msg)
|
||||
else:
|
||||
if enrollment_attributes is not None:
|
||||
set_enrollment_attributes(username, course_id, enrollment_attributes)
|
||||
log.info(u'Course Enrollment updated for user {user} in course {course} to mode {mode}'.format(
|
||||
log.info('Course Enrollment updated for user {user} in course {course} to mode {mode}'.format(
|
||||
user=username,
|
||||
course=course_id,
|
||||
mode=mode
|
||||
@@ -320,16 +320,13 @@ def get_course_enrollment_details(course_id, include_expired=False):
|
||||
}
|
||||
|
||||
"""
|
||||
cache_key = u'enrollment.course.details.{course_id}.{include_expired}'.format(
|
||||
course_id=course_id,
|
||||
include_expired=include_expired
|
||||
)
|
||||
cache_key = f'enrollment.course.details.{course_id}.{include_expired}'
|
||||
cached_enrollment_data = None
|
||||
try:
|
||||
cached_enrollment_data = cache.get(cache_key)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# The cache backend could raise an exception (for example, memcache keys that contain spaces)
|
||||
log.exception(u"Error occurred while retrieving course enrollment details from the cache")
|
||||
log.exception("Error occurred while retrieving course enrollment details from the cache")
|
||||
|
||||
if cached_enrollment_data:
|
||||
return cached_enrollment_data
|
||||
@@ -341,8 +338,8 @@ def get_course_enrollment_details(course_id, include_expired=False):
|
||||
cache.set(cache_key, course_enrollment_details, cache_time_out)
|
||||
except Exception:
|
||||
# Catch any unexpected errors during caching.
|
||||
log.exception(u"Error occurred while caching course enrollment details for course %s", course_id)
|
||||
raise errors.CourseEnrollmentError(u"An unexpected error occurred while retrieving course enrollment details.") # lint-amnesty, pylint: disable=raise-missing-from
|
||||
log.exception("Error occurred while caching course enrollment details for course %s", course_id)
|
||||
raise errors.CourseEnrollmentError("An unexpected error occurred while retrieving course enrollment details.") # lint-amnesty, pylint: disable=raise-missing-from
|
||||
|
||||
return course_enrollment_details
|
||||
|
||||
@@ -449,8 +446,8 @@ def validate_course_mode(course_id, mode, is_active=None, include_expired=False)
|
||||
available_modes = [m['slug'] for m in course_modes]
|
||||
if mode not in available_modes:
|
||||
msg = (
|
||||
u"Specified course mode '{mode}' unavailable for course {course_id}. "
|
||||
u"Available modes were: {available}"
|
||||
"Specified course mode '{mode}' unavailable for course {course_id}. "
|
||||
"Available modes were: {available}"
|
||||
).format(
|
||||
mode=mode,
|
||||
course_id=course_id,
|
||||
@@ -550,5 +547,5 @@ def _data_api():
|
||||
try:
|
||||
return importlib.import_module(api_path)
|
||||
except (ImportError, ValueError):
|
||||
log.exception(u"Could not load module at '{path}'".format(path=api_path))
|
||||
log.exception(f"Could not load module at '{api_path}'")
|
||||
raise errors.EnrollmentApiLoadError(api_path) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
"""
|
||||
Enrollments Application Configuration
|
||||
|
||||
@@ -15,7 +14,7 @@ class EnrollmentsConfig(AppConfig):
|
||||
"""
|
||||
Application Configuration for Enrollments.
|
||||
"""
|
||||
name = u'openedx.core.djangoapps.enrollments'
|
||||
name = 'openedx.core.djangoapps.enrollments'
|
||||
|
||||
def ready(self):
|
||||
"""
|
||||
|
||||
@@ -9,7 +9,6 @@ import logging
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.db import transaction
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from six import text_type
|
||||
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.enrollments.errors import (
|
||||
@@ -69,8 +68,8 @@ def get_course_enrollments(username, include_inactive=False):
|
||||
if deleted:
|
||||
log.warning(
|
||||
(
|
||||
u"Course enrollments for user %s reference "
|
||||
u"courses that do not exist (this can occur if a course is deleted)."
|
||||
"Course enrollments for user %s reference "
|
||||
"courses that do not exist (this can occur if a course is deleted)."
|
||||
), username,
|
||||
)
|
||||
|
||||
@@ -142,7 +141,7 @@ def create_course_enrollment(username, course_id, mode, is_active):
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
msg = u"Not user with username '{username}' found.".format(username=username)
|
||||
msg = f"Not user with username '{username}' found."
|
||||
log.warning(msg)
|
||||
raise UserNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
|
||||
@@ -150,14 +149,14 @@ def create_course_enrollment(username, course_id, mode, is_active):
|
||||
enrollment = CourseEnrollment.enroll(user, course_key, check_access=True)
|
||||
return _update_enrollment(enrollment, is_active=is_active, mode=mode)
|
||||
except NonExistentCourseError as err:
|
||||
raise CourseNotFoundError(text_type(err)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
raise CourseNotFoundError(str(err)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
except EnrollmentClosedError as err:
|
||||
raise CourseEnrollmentClosedError(text_type(err)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
raise CourseEnrollmentClosedError(str(err)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
except CourseFullError as err:
|
||||
raise CourseEnrollmentFullError(text_type(err)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
raise CourseEnrollmentFullError(str(err)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
except AlreadyEnrolledError as err:
|
||||
enrollment = get_course_enrollment(username, course_id)
|
||||
raise CourseEnrollmentExistsError(text_type(err), enrollment) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
raise CourseEnrollmentExistsError(str(err), enrollment) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
|
||||
|
||||
def update_course_enrollment(username, course_id, mode=None, is_active=None):
|
||||
@@ -180,7 +179,7 @@ def update_course_enrollment(username, course_id, mode=None, is_active=None):
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
msg = u"Not user with username '{username}' found.".format(username=username)
|
||||
msg = f"Not user with username '{username}' found."
|
||||
log.warning(msg)
|
||||
raise UserNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
|
||||
@@ -257,7 +256,7 @@ def unenroll_user_from_all_courses(username):
|
||||
for enrollment in enrollments:
|
||||
_update_enrollment(enrollment, is_active=False)
|
||||
|
||||
return set([str(enrollment.course_id.org) for enrollment in enrollments]) # lint-amnesty, pylint: disable=consider-using-set-comprehension
|
||||
return {str(enrollment.course_id.org) for enrollment in enrollments} # lint-amnesty, pylint: disable=consider-using-set-comprehension
|
||||
|
||||
|
||||
def _get_user(username):
|
||||
@@ -271,7 +270,7 @@ def _get_user(username):
|
||||
try:
|
||||
return User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
msg = u"Not user with username '{username}' found.".format(username=username)
|
||||
msg = f"Not user with username '{username}' found."
|
||||
log.warning(msg)
|
||||
raise UserNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
|
||||
@@ -294,17 +293,17 @@ def _invalid_attribute(attributes):
|
||||
invalid_attributes = []
|
||||
for attribute in attributes:
|
||||
if "namespace" not in attribute:
|
||||
msg = u"'namespace' not in enrollment attribute"
|
||||
msg = "'namespace' not in enrollment attribute"
|
||||
log.warning(msg)
|
||||
invalid_attributes.append("namespace")
|
||||
raise InvalidEnrollmentAttribute(msg)
|
||||
if "name" not in attribute:
|
||||
msg = u"'name' not in enrollment attribute"
|
||||
msg = "'name' not in enrollment attribute"
|
||||
log.warning(msg)
|
||||
invalid_attributes.append("name")
|
||||
raise InvalidEnrollmentAttribute(msg)
|
||||
if "value" not in attribute:
|
||||
msg = u"'value' not in enrollment attribute"
|
||||
msg = "'value' not in enrollment attribute"
|
||||
log.warning(msg)
|
||||
invalid_attributes.append("value")
|
||||
raise InvalidEnrollmentAttribute(msg)
|
||||
@@ -335,7 +334,7 @@ def get_course_enrollment_info(course_id, include_expired=False):
|
||||
try:
|
||||
course = CourseOverview.get_from_id(course_key)
|
||||
except CourseOverview.DoesNotExist:
|
||||
msg = u"Requested enrollment information for unknown course {course}".format(course=course_id)
|
||||
msg = f"Requested enrollment information for unknown course {course_id}"
|
||||
log.warning(msg)
|
||||
raise CourseNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
else:
|
||||
|
||||
@@ -8,7 +8,7 @@ class CourseEnrollmentError(Exception):
|
||||
|
||||
"""
|
||||
def __init__(self, msg, data=None):
|
||||
super(CourseEnrollmentError, self).__init__(msg) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__(msg)
|
||||
# Corresponding information to help resolve the error.
|
||||
self.data = data
|
||||
|
||||
@@ -29,7 +29,7 @@ class CourseEnrollmentExistsError(CourseEnrollmentError): # lint-amnesty, pylin
|
||||
enrollment = None
|
||||
|
||||
def __init__(self, message, enrollment):
|
||||
super(CourseEnrollmentExistsError, self).__init__(message) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__(message)
|
||||
self.enrollment = enrollment
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class CourseEnrollmentsApiListForm(Form):
|
||||
try:
|
||||
return CourseKey.from_string(course_id)
|
||||
except InvalidKeyError:
|
||||
raise ValidationError(u"'{}' is not a valid course id.".format(course_id)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
raise ValidationError(f"'{course_id}' is not a valid course id.") # lint-amnesty, pylint: disable=raise-missing-from
|
||||
return course_id
|
||||
|
||||
def clean_username(self):
|
||||
@@ -40,7 +40,7 @@ class CourseEnrollmentsApiListForm(Form):
|
||||
usernames = usernames_csv_string.split(',')
|
||||
if len(usernames) > self.MAX_USERNAME_COUNT:
|
||||
raise ValidationError(
|
||||
u"Too many usernames in a single request - {}. A maximum of {} is allowed".format(
|
||||
"Too many usernames in a single request - {}. A maximum of {} is allowed".format(
|
||||
len(usernames),
|
||||
self.MAX_USERNAME_COUNT,
|
||||
)
|
||||
|
||||
@@ -14,8 +14,6 @@ from common.djangoapps.student.tests.factories import UserFactory
|
||||
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
import six # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from six.moves import range # lint-amnesty, pylint: disable=wrong-import-order
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -27,12 +25,12 @@ class EnrollManagementCommandTest(SharedModuleStoreTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(EnrollManagementCommandTest, cls).setUpClass()
|
||||
super().setUpClass()
|
||||
cls.course = CourseFactory.create(org='fooX', number='007')
|
||||
|
||||
def setUp(self):
|
||||
super(EnrollManagementCommandTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
self.course_id = six.text_type(self.course.id)
|
||||
super().setUp()
|
||||
self.course_id = str(self.course.id)
|
||||
self.username = 'ralph' + uuid4().hex
|
||||
self.user_email = self.username + '@example.com'
|
||||
|
||||
|
||||
@@ -45,13 +45,13 @@ class CourseSerializer(serializers.Serializer): # pylint: disable=abstract-meth
|
||||
invite_only = serializers.BooleanField(source="invitation_only")
|
||||
course_modes = serializers.SerializerMethodField()
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
# For disambiguating within the drf-yasg swagger schema
|
||||
ref_name = 'enrollment.Course'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.include_expired = kwargs.pop("include_expired", False)
|
||||
super(CourseSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_course_modes(self, obj):
|
||||
"""
|
||||
@@ -82,7 +82,7 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer):
|
||||
"""Retrieves the username from the associated model."""
|
||||
return model.username
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
model = CourseEnrollment
|
||||
fields = ('created', 'mode', 'is_active', 'course_details', 'user')
|
||||
lookup_field = 'username'
|
||||
@@ -96,7 +96,7 @@ class CourseEnrollmentsApiListSerializer(CourseEnrollmentSerializer):
|
||||
course_id = serializers.CharField(source='course_overview.id')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CourseEnrollmentsApiListSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields.pop('course_details')
|
||||
|
||||
class Meta(CourseEnrollmentSerializer.Meta):
|
||||
|
||||
@@ -13,7 +13,7 @@ from common.djangoapps.student.models import CourseEnrollment
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
|
||||
class EnrollmentsService(object):
|
||||
class EnrollmentsService:
|
||||
"""
|
||||
Enrollments service
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ Tests for student enrollment.
|
||||
|
||||
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import ddt
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.test.utils import override_settings
|
||||
from mock import Mock, patch
|
||||
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from openedx.core.djangoapps.enrollments import api
|
||||
@@ -33,7 +33,7 @@ class EnrollmentTest(CacheIsolationTestCase):
|
||||
ENABLED_CACHES = ['default']
|
||||
|
||||
def setUp(self):
|
||||
super(EnrollmentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
fake_data_api.reset()
|
||||
|
||||
@ddt.data(
|
||||
|
||||
@@ -6,14 +6,12 @@ Test the Data Aggregation Layer for Course Enrollments.
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import ddt
|
||||
import pytest
|
||||
import six
|
||||
from django.conf import settings
|
||||
from mock import patch
|
||||
from pytz import UTC
|
||||
from six.moves import range
|
||||
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
|
||||
@@ -45,7 +43,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Create a course and user, then log in. """
|
||||
super(EnrollmentDataTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course = CourseFactory.create()
|
||||
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
|
||||
self.client.login(username=self.USERNAME, password=self.PASSWORD)
|
||||
@@ -66,7 +64,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
self._create_course_modes(course_modes)
|
||||
enrollment = data.create_course_enrollment(
|
||||
self.user.username,
|
||||
six.text_type(self.course.id),
|
||||
str(self.course.id),
|
||||
enrollment_mode,
|
||||
True
|
||||
)
|
||||
@@ -87,7 +85,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
|
||||
enrollment = data.update_course_enrollment(
|
||||
self.user.username,
|
||||
six.text_type(self.course.id),
|
||||
str(self.course.id),
|
||||
is_active=False
|
||||
)
|
||||
|
||||
@@ -106,7 +104,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
)
|
||||
def test_get_course_info(self, course_modes):
|
||||
self._create_course_modes(course_modes, course=self.course)
|
||||
result_course = data.get_course_enrollment_info(six.text_type(self.course.id))
|
||||
result_course = data.get_course_enrollment_info(str(self.course.id))
|
||||
result_slugs = [mode['slug'] for mode in result_course['course_modes']]
|
||||
for course_mode in course_modes:
|
||||
assert course_mode in result_slugs
|
||||
@@ -131,7 +129,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
# Create the original enrollment.
|
||||
created_enrollments.append(data.create_course_enrollment(
|
||||
self.user.username,
|
||||
six.text_type(course.id),
|
||||
str(course.id),
|
||||
'honor',
|
||||
True
|
||||
))
|
||||
@@ -172,7 +170,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
# Create the original enrollment.
|
||||
created_enrollments.append(data.create_course_enrollment(
|
||||
self.user.username,
|
||||
six.text_type(course.id),
|
||||
str(course.id),
|
||||
'honor',
|
||||
True
|
||||
))
|
||||
@@ -180,7 +178,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
# deactivate one enrollment
|
||||
data.update_course_enrollment(
|
||||
self.user.username,
|
||||
six.text_type(created_courses[0].id),
|
||||
str(created_courses[0].id),
|
||||
'honor',
|
||||
False
|
||||
)
|
||||
@@ -208,18 +206,18 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
self._create_course_modes(course_modes)
|
||||
|
||||
# Try to get an enrollment before it exists.
|
||||
result = data.get_course_enrollment(self.user.username, six.text_type(self.course.id))
|
||||
result = data.get_course_enrollment(self.user.username, str(self.course.id))
|
||||
assert result is None
|
||||
|
||||
# Create the original enrollment.
|
||||
enrollment = data.create_course_enrollment(
|
||||
self.user.username,
|
||||
six.text_type(self.course.id),
|
||||
str(self.course.id),
|
||||
enrollment_mode,
|
||||
True
|
||||
)
|
||||
# Get the enrollment and compare it to the original.
|
||||
result = data.get_course_enrollment(self.user.username, six.text_type(self.course.id))
|
||||
result = data.get_course_enrollment(self.user.username, str(self.course.id))
|
||||
assert self.user.username == result['user']
|
||||
assert enrollment == result
|
||||
|
||||
@@ -255,7 +253,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
for user in users:
|
||||
created_enrollments.append(data.create_course_enrollment(
|
||||
user.username,
|
||||
six.text_type(self.course.id),
|
||||
str(self.course.id),
|
||||
enrollment_mode,
|
||||
True
|
||||
))
|
||||
@@ -282,7 +280,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
def test_add_or_update_enrollment_attr(self, course_modes, enrollment_mode):
|
||||
# Create the course modes (if any) required for this test case
|
||||
self._create_course_modes(course_modes)
|
||||
data.create_course_enrollment(self.user.username, six.text_type(self.course.id), enrollment_mode, True)
|
||||
data.create_course_enrollment(self.user.username, str(self.course.id), enrollment_mode, True)
|
||||
enrollment_attributes = [
|
||||
{
|
||||
"namespace": "credit",
|
||||
@@ -291,8 +289,8 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
}
|
||||
]
|
||||
|
||||
data.add_or_update_enrollment_attr(self.user.username, six.text_type(self.course.id), enrollment_attributes)
|
||||
enrollment_attr = data.get_enrollment_attributes(self.user.username, six.text_type(self.course.id))
|
||||
data.add_or_update_enrollment_attr(self.user.username, str(self.course.id), enrollment_attributes)
|
||||
enrollment_attr = data.get_enrollment_attributes(self.user.username, str(self.course.id))
|
||||
assert enrollment_attr[0] == enrollment_attributes[0]
|
||||
|
||||
enrollment_attributes = [
|
||||
@@ -303,8 +301,8 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
}
|
||||
]
|
||||
|
||||
data.add_or_update_enrollment_attr(self.user.username, six.text_type(self.course.id), enrollment_attributes)
|
||||
enrollment_attr = data.get_enrollment_attributes(self.user.username, six.text_type(self.course.id))
|
||||
data.add_or_update_enrollment_attr(self.user.username, str(self.course.id), enrollment_attributes)
|
||||
enrollment_attr = data.get_enrollment_attributes(self.user.username, str(self.course.id))
|
||||
assert enrollment_attr[0] == enrollment_attributes[0]
|
||||
|
||||
def test_non_existent_course(self):
|
||||
@@ -323,7 +321,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
|
||||
def test_enrollment_for_non_existent_user(self):
|
||||
with pytest.raises(UserNotFoundError):
|
||||
data.create_course_enrollment("some_fake_user", six.text_type(self.course.id), 'honor', True)
|
||||
data.create_course_enrollment("some_fake_user", str(self.course.id), 'honor', True)
|
||||
|
||||
def test_enrollment_for_non_existent_course(self):
|
||||
with pytest.raises(CourseNotFoundError):
|
||||
@@ -333,23 +331,23 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
def test_enrollment_for_closed_course(self, mock_enroll):
|
||||
mock_enroll.side_effect = EnrollmentClosedError("Bad things happened")
|
||||
with pytest.raises(CourseEnrollmentClosedError):
|
||||
data.create_course_enrollment(self.user.username, six.text_type(self.course.id), 'honor', True)
|
||||
data.create_course_enrollment(self.user.username, str(self.course.id), 'honor', True)
|
||||
|
||||
@patch.object(CourseEnrollment, "enroll")
|
||||
def test_enrollment_for_full_course(self, mock_enroll):
|
||||
mock_enroll.side_effect = CourseFullError("Bad things happened")
|
||||
with pytest.raises(CourseEnrollmentFullError):
|
||||
data.create_course_enrollment(self.user.username, six.text_type(self.course.id), 'honor', True)
|
||||
data.create_course_enrollment(self.user.username, str(self.course.id), 'honor', True)
|
||||
|
||||
@patch.object(CourseEnrollment, "enroll")
|
||||
def test_enrollment_for_enrolled_course(self, mock_enroll):
|
||||
mock_enroll.side_effect = AlreadyEnrolledError("Bad things happened")
|
||||
with pytest.raises(CourseEnrollmentExistsError):
|
||||
data.create_course_enrollment(self.user.username, six.text_type(self.course.id), 'honor', True)
|
||||
data.create_course_enrollment(self.user.username, str(self.course.id), 'honor', True)
|
||||
|
||||
def test_update_for_non_existent_user(self):
|
||||
with pytest.raises(UserNotFoundError):
|
||||
data.update_course_enrollment("some_fake_user", six.text_type(self.course.id), is_active=False)
|
||||
data.update_course_enrollment("some_fake_user", str(self.course.id), is_active=False)
|
||||
|
||||
def test_update_for_non_existent_course(self):
|
||||
enrollment = data.update_course_enrollment(self.user.username, "some/fake/course", is_active=False)
|
||||
@@ -378,7 +376,7 @@ class EnrollmentDataTest(ModuleStoreTestCase):
|
||||
|
||||
def assert_enrollment_modes(self, expected_modes, include_expired):
|
||||
"""Get enrollment data and assert response with expected modes."""
|
||||
result_course = data.get_course_enrollment_info(six.text_type(self.course.id), include_expired=include_expired)
|
||||
result_course = data.get_course_enrollment_info(str(self.course.id), include_expired=include_expired)
|
||||
result_slugs = [mode['slug'] for mode in result_course['course_modes']]
|
||||
for course_mode in expected_modes:
|
||||
assert course_mode in result_slugs
|
||||
|
||||
@@ -36,8 +36,8 @@ class EnrollmentsServiceTests(ModuleStoreTestCase):
|
||||
|
||||
CourseModeFactory.create(mode_slug=course_mode, course_id=course_id)
|
||||
user = UserFactory(
|
||||
username='user{}'.format(index),
|
||||
email='LEARNER{}@example.com'.format(index)
|
||||
username=f'user{index}',
|
||||
email=f'LEARNER{index}@example.com'
|
||||
)
|
||||
CourseEnrollment.enroll(user, course_id, mode=course_mode)
|
||||
|
||||
@@ -186,7 +186,7 @@ class EnrollmentsServicePerformanceTests(ModuleStoreTestCase):
|
||||
def create_and_enroll_users(self, num_users):
|
||||
num_course_modes = len(self.course_modes)
|
||||
for index in range(num_users):
|
||||
user = UserFactory(username='user{}'.format(index))
|
||||
user = UserFactory(username=f'user{index}')
|
||||
CourseEnrollment.enroll(user, self.course.id, mode=self.course_modes[index % num_course_modes])
|
||||
|
||||
@ddt.data(10, 25, 50)
|
||||
|
||||
@@ -8,11 +8,11 @@ import datetime
|
||||
import itertools
|
||||
import json
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
import ddt
|
||||
import httpretty
|
||||
import pytz
|
||||
import six
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
@@ -21,11 +21,8 @@ from django.test import Client
|
||||
from django.test.utils import override_settings
|
||||
from django.urls import reverse
|
||||
from freezegun import freeze_time
|
||||
from mock import patch
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APITestCase
|
||||
from six import text_type
|
||||
from six.moves import range
|
||||
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
|
||||
@@ -50,7 +47,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls_range
|
||||
|
||||
|
||||
class EnrollmentTestMixin(object):
|
||||
class EnrollmentTestMixin:
|
||||
""" Mixin with methods useful for testing enrollments. """
|
||||
API_KEY = "i am a key"
|
||||
|
||||
@@ -76,7 +73,7 @@ class EnrollmentTestMixin(object):
|
||||
Returns
|
||||
Response
|
||||
"""
|
||||
course_id = course_id or six.text_type(self.course.id)
|
||||
course_id = course_id or str(self.course.id)
|
||||
username = username or self.user.username
|
||||
|
||||
data = {
|
||||
@@ -171,7 +168,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
|
||||
def setUp(self):
|
||||
""" Create a course and user, then log in. """
|
||||
super(EnrollmentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
|
||||
self.rate_limit_config = RateLimitConfiguration.current()
|
||||
self.rate_limit_config.enabled = False
|
||||
@@ -240,19 +237,19 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
resp = self.client.get(
|
||||
reverse(
|
||||
'courseenrollment',
|
||||
kwargs={'username': self.user.username, "course_id": six.text_type(self.course.id)},
|
||||
kwargs={'username': self.user.username, "course_id": str(self.course.id)},
|
||||
)
|
||||
)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
data = json.loads(resp.content.decode('utf-8'))
|
||||
assert six.text_type(self.course.id) == data['course_details']['course_id']
|
||||
assert str(self.course.id) == data['course_details']['course_id']
|
||||
assert self.course.display_name_with_default == data['course_details']['course_name']
|
||||
assert CourseMode.DEFAULT_MODE_SLUG == data['mode']
|
||||
assert data['is_active']
|
||||
|
||||
@ddt.data(
|
||||
(True, u"True"),
|
||||
(False, u"False"),
|
||||
(True, "True"),
|
||||
(False, "False"),
|
||||
(None, None)
|
||||
)
|
||||
@ddt.unpack
|
||||
@@ -289,7 +286,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
# While the enrollment wrong is invalid, the response content should have
|
||||
# all the valid enrollment modes.
|
||||
data = json.loads(resp.content.decode('utf-8'))
|
||||
assert six.text_type(self.course.id) == data['course_details']['course_id']
|
||||
assert str(self.course.id) == data['course_details']['course_id']
|
||||
assert 1 == len(data['course_details']['course_modes'])
|
||||
assert 'professional' == data['course_details']['course_modes'][0]['slug']
|
||||
|
||||
@@ -302,11 +299,11 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
# Create an enrollment
|
||||
self.assert_enrollment_status()
|
||||
resp = self.client.get(
|
||||
reverse('courseenrollment', kwargs={"course_id": six.text_type(self.course.id)})
|
||||
reverse('courseenrollment', kwargs={"course_id": str(self.course.id)})
|
||||
)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
data = json.loads(resp.content.decode('utf-8'))
|
||||
assert six.text_type(self.course.id) == data['course_details']['course_id']
|
||||
assert str(self.course.id) == data['course_details']['course_id']
|
||||
assert CourseMode.DEFAULT_MODE_SLUG == data['mode']
|
||||
assert data['is_active']
|
||||
|
||||
@@ -363,10 +360,9 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
response = self.client.get(reverse('courseenrollments'), {'user': self.user.username}, **kwargs)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = json.loads(response.content.decode('utf-8'))
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
self.assertCountEqual(
|
||||
[(datum['course_details']['course_id'], datum['course_details']['course_name']) for datum in data],
|
||||
[(six.text_type(course.id), course.display_name_with_default) for course in courses]
|
||||
[(str(course.id), course.display_name_with_default) for course in courses]
|
||||
)
|
||||
|
||||
def test_enrollment_list_permissions(self):
|
||||
@@ -378,12 +374,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
other_course = CourseFactory.create(emit_signals=True)
|
||||
for course in self.course, other_course:
|
||||
CourseModeFactory.create(
|
||||
course_id=six.text_type(course.id),
|
||||
course_id=str(course.id),
|
||||
mode_slug=CourseMode.DEFAULT_MODE_SLUG,
|
||||
mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
|
||||
)
|
||||
self.assert_enrollment_status(
|
||||
course_id=six.text_type(course.id),
|
||||
course_id=str(course.id),
|
||||
max_mongo_calls=0,
|
||||
)
|
||||
# Verify the user himself can see both of his enrollments.
|
||||
@@ -416,7 +412,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
mode_display_name=CourseMode.HONOR,
|
||||
)
|
||||
url = reverse('courseenrollment',
|
||||
kwargs={'username': self.other_user.username, "course_id": six.text_type(self.course.id)})
|
||||
kwargs={'username': self.other_user.username, "course_id": str(self.course.id)})
|
||||
|
||||
response = self.client.get(url)
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
@@ -441,12 +437,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
bulk_sku="BULK123"
|
||||
)
|
||||
resp = self.client.get(
|
||||
reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(self.course.id)})
|
||||
reverse('courseenrollmentdetails', kwargs={"course_id": str(self.course.id)})
|
||||
)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
|
||||
data = json.loads(resp.content.decode('utf-8'))
|
||||
assert six.text_type(self.course.id) == data['course_id']
|
||||
assert str(self.course.id) == data['course_id']
|
||||
assert self.course.display_name_with_default == data['course_name']
|
||||
mode = data['course_modes'][0]
|
||||
assert mode['slug'] == CourseMode.HONOR
|
||||
@@ -461,12 +457,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
mode_display_name=CourseMode.CREDIT_MODE,
|
||||
)
|
||||
resp = self.client.get(
|
||||
reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(self.course.id)})
|
||||
reverse('courseenrollmentdetails', kwargs={"course_id": str(self.course.id)})
|
||||
)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
|
||||
data = json.loads(resp.content.decode('utf-8'))
|
||||
assert six.text_type(self.course.id) == data['course_id']
|
||||
assert str(self.course.id) == data['course_id']
|
||||
mode = data['course_modes'][0]
|
||||
assert mode['slug'] == CourseMode.CREDIT_MODE
|
||||
assert mode['name'] == CourseMode.CREDIT_MODE
|
||||
@@ -492,10 +488,10 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
# miss; the modulestore is queried and course metadata is cached.
|
||||
__ = CourseOverview.get_from_id(course.id)
|
||||
|
||||
self.assert_enrollment_status(course_id=six.text_type(course.id))
|
||||
self.assert_enrollment_status(course_id=str(course.id))
|
||||
|
||||
# Check course details
|
||||
url = reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(course.id)})
|
||||
url = reverse('courseenrollmentdetails', kwargs={"course_id": str(course.id)})
|
||||
resp = self.client.get(url)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
|
||||
@@ -504,7 +500,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
assert data['course_end'] == expected_end
|
||||
|
||||
# Check enrollment course details
|
||||
url = reverse('courseenrollment', kwargs={"course_id": six.text_type(course.id)})
|
||||
url = reverse('courseenrollment', kwargs={"course_id": str(course.id)})
|
||||
resp = self.client.get(url)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
|
||||
@@ -540,7 +536,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
resp = self.client.get(
|
||||
reverse(
|
||||
'courseenrollment',
|
||||
kwargs={'username': self.user.username, "course_id": six.text_type(self.course.id)},
|
||||
kwargs={'username': self.user.username, "course_id": str(self.course.id)},
|
||||
)
|
||||
)
|
||||
assert resp.status_code == status.HTTP_400_BAD_REQUEST
|
||||
@@ -592,7 +588,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
try:
|
||||
throttle.parse_rate(throttle.get_rate())
|
||||
except ImproperlyConfigured:
|
||||
self.fail(u"No throttle rate set for {}".format(user_scope))
|
||||
self.fail(f"No throttle rate set for {user_scope}")
|
||||
|
||||
def test_create_enrollment_with_cohort(self):
|
||||
"""Enroll in the course, and also add to a cohort."""
|
||||
@@ -654,7 +650,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
v_response = self.client.get(
|
||||
reverse(
|
||||
'courseenrollmentdetails',
|
||||
kwargs={"course_id": six.text_type(self.course.id)}
|
||||
kwargs={"course_id": str(self.course.id)}
|
||||
),
|
||||
{'include_expired': True},
|
||||
)
|
||||
@@ -665,7 +661,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
|
||||
# Omits the include_expired parameter from the API call
|
||||
h_response = self.client.get(
|
||||
reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(self.course.id)}),
|
||||
reverse('courseenrollmentdetails', kwargs={"course_id": str(self.course.id)}),
|
||||
)
|
||||
h_data = json.loads(h_response.content.decode('utf-8'))
|
||||
|
||||
@@ -1079,7 +1075,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente
|
||||
)
|
||||
consent_kwargs = {
|
||||
'username': self.user.username,
|
||||
'course_id': six.text_type(self.course.id),
|
||||
'course_id': str(self.course.id),
|
||||
'ec_uuid': 'this-is-a-real-uuid'
|
||||
}
|
||||
mock_enterprise_customer_from_api.return_value = FAKE_ENTERPRISE_CUSTOMER
|
||||
@@ -1158,7 +1154,7 @@ class EnrollmentEmbargoTest(EnrollmentTestMixin, UrlResetMixin, ModuleStoreTestC
|
||||
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
||||
def setUp(self):
|
||||
""" Create a course and user, then log in. """
|
||||
super(EnrollmentEmbargoTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
|
||||
self.course = CourseFactory.create()
|
||||
# Load a CourseOverview. This initial load should result in a cache
|
||||
@@ -1172,7 +1168,7 @@ class EnrollmentEmbargoTest(EnrollmentTestMixin, UrlResetMixin, ModuleStoreTestC
|
||||
def _generate_data(self):
|
||||
return json.dumps({
|
||||
'course_details': {
|
||||
'course_id': six.text_type(self.course.id)
|
||||
'course_id': str(self.course.id)
|
||||
},
|
||||
'user': self.user.username
|
||||
})
|
||||
@@ -1288,7 +1284,7 @@ class EnrollmentCrossDomainTest(ModuleStoreTestCase):
|
||||
|
||||
def setUp(self):
|
||||
""" Create a course and user, then log in. """
|
||||
super(EnrollmentCrossDomainTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course = CourseFactory.create()
|
||||
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
|
||||
|
||||
@@ -1312,7 +1308,7 @@ class EnrollmentCrossDomainTest(ModuleStoreTestCase):
|
||||
def _get_csrf_cookie(self):
|
||||
"""Retrieve the cross-domain CSRF cookie. """
|
||||
url = reverse('courseenrollment', kwargs={
|
||||
'course_id': six.text_type(self.course.id)
|
||||
'course_id': str(self.course.id)
|
||||
})
|
||||
resp = self.client.get(url, HTTP_REFERER=self.REFERER)
|
||||
assert resp.status_code == 200
|
||||
@@ -1324,7 +1320,7 @@ class EnrollmentCrossDomainTest(ModuleStoreTestCase):
|
||||
url = reverse('courseenrollments')
|
||||
params = json.dumps({
|
||||
'course_details': {
|
||||
'course_id': six.text_type(self.course.id),
|
||||
'course_id': str(self.course.id),
|
||||
},
|
||||
'user': self.user.username
|
||||
})
|
||||
@@ -1351,7 +1347,7 @@ class UnenrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase):
|
||||
|
||||
def setUp(self):
|
||||
""" Create a course and user, then log in. """
|
||||
super(UnenrollmentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.superuser = SuperuserFactory()
|
||||
# Pass emit_signals when creating the course so it would be cached
|
||||
# as a CourseOverview. Enrollments require a cached CourseOverview.
|
||||
@@ -1431,7 +1427,7 @@ class UnenrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase):
|
||||
response = self._submit_unenroll(self.superuser, None)
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
data = json.loads(response.content.decode('utf-8'))
|
||||
assert data == u'Username not specified.'
|
||||
assert data == 'Username not specified.'
|
||||
self._assert_active()
|
||||
|
||||
def test_deactivate_enrollments_empty_username(self):
|
||||
@@ -1495,7 +1491,7 @@ class UserRoleTest(ModuleStoreTestCase):
|
||||
|
||||
def setUp(self):
|
||||
""" Create a course and user, then log in. """
|
||||
super(UserRoleTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course1 = CourseFactory.create(emit_signals=True, org="org1", course="course1", run="run1")
|
||||
self.course2 = CourseFactory.create(emit_signals=True, org="org2", course="course2", run="run2")
|
||||
self.user = UserFactory.create(
|
||||
@@ -1514,7 +1510,7 @@ class UserRoleTest(ModuleStoreTestCase):
|
||||
def _create_expected_role_dict(self, course, role):
|
||||
""" Creates the expected role dict object that the view should return """
|
||||
return {
|
||||
'course_id': text_type(course.id),
|
||||
'course_id': str(course.id),
|
||||
'org': course.org,
|
||||
'role': role.ROLE,
|
||||
}
|
||||
@@ -1570,8 +1566,8 @@ class UserRoleTest(ModuleStoreTestCase):
|
||||
role2 = CourseStaffRole(self.course2.id)
|
||||
role2.add_users(self.user)
|
||||
expected_role2 = self._create_expected_role_dict(self.course2, role2)
|
||||
self._assert_roles([expected_role1], False, course_id=text_type(self.course1.id))
|
||||
self._assert_roles([expected_role2], False, course_id=text_type(self.course2.id))
|
||||
self._assert_roles([expected_role1], False, course_id=str(self.course1.id))
|
||||
self._assert_roles([expected_role2], False, course_id=str(self.course2.id))
|
||||
|
||||
def test_roles_exception(self):
|
||||
with patch('openedx.core.djangoapps.enrollments.api.get_user_roles') as mock_get_user_roles:
|
||||
@@ -1580,7 +1576,7 @@ class UserRoleTest(ModuleStoreTestCase):
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
expected_response = {
|
||||
"message": (
|
||||
u"An error occurred while retrieving roles for user '{username}"
|
||||
"An error occurred while retrieving roles for user '{username}"
|
||||
).format(username=self.user.username)
|
||||
}
|
||||
response_data = json.loads(response.content.decode('utf-8'))
|
||||
@@ -1596,7 +1592,7 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase):
|
||||
CREATED_DATA = datetime.datetime(2018, 1, 1, 0, 0, 1, tzinfo=pytz.UTC)
|
||||
|
||||
def setUp(self):
|
||||
super(CourseEnrollmentsApiListTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.rate_limit_config = RateLimitConfiguration.current()
|
||||
self.rate_limit_config.enabled = False
|
||||
self.rate_limit_config.save()
|
||||
@@ -1641,31 +1637,31 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase):
|
||||
with freeze_time(self.CREATED_DATA):
|
||||
data.create_course_enrollment(
|
||||
self.student1.username,
|
||||
six.text_type(self.course.id),
|
||||
str(self.course.id),
|
||||
'honor',
|
||||
True
|
||||
)
|
||||
data.create_course_enrollment(
|
||||
self.student2.username,
|
||||
six.text_type(self.course.id),
|
||||
str(self.course.id),
|
||||
'honor',
|
||||
True
|
||||
)
|
||||
data.create_course_enrollment(
|
||||
self.student3.username,
|
||||
six.text_type(self.course2.id),
|
||||
str(self.course2.id),
|
||||
'verified',
|
||||
True
|
||||
)
|
||||
data.create_course_enrollment(
|
||||
self.student2.username,
|
||||
six.text_type(self.course2.id),
|
||||
str(self.course2.id),
|
||||
'honor',
|
||||
True
|
||||
)
|
||||
data.create_course_enrollment(
|
||||
self.staff_user.username,
|
||||
six.text_type(self.course2.id),
|
||||
str(self.course2.id),
|
||||
'verified',
|
||||
True
|
||||
)
|
||||
@@ -1742,4 +1738,4 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase):
|
||||
content = self._assert_list_of_enrollments(query_params, status.HTTP_200_OK)
|
||||
results = content['results']
|
||||
|
||||
six.assertCountEqual(self, results, expected_results)
|
||||
self.assertCountEqual(results, expected_results)
|
||||
|
||||
@@ -21,11 +21,11 @@ urlpatterns = [
|
||||
username=settings.USERNAME_PATTERN,
|
||||
course_key=settings.COURSE_ID_PATTERN),
|
||||
EnrollmentView.as_view(), name='courseenrollment'),
|
||||
url(r'^enrollment/{course_key}$'.format(course_key=settings.COURSE_ID_PATTERN),
|
||||
url(fr'^enrollment/{settings.COURSE_ID_PATTERN}$',
|
||||
EnrollmentView.as_view(), name='courseenrollment'),
|
||||
url(r'^enrollment$', EnrollmentListView.as_view(), name='courseenrollments'),
|
||||
url(r'^enrollments/?$', CourseEnrollmentsApiListView.as_view(), name='courseenrollmentsapilist'),
|
||||
url(r'^course/{course_key}$'.format(course_key=settings.COURSE_ID_PATTERN),
|
||||
url(fr'^course/{settings.COURSE_ID_PATTERN}$',
|
||||
EnrollmentCourseDetailView.as_view(), name='courseenrollmentdetails'),
|
||||
url(r'^unenroll/$', UnenrollmentView.as_view(), name='unenrollment'),
|
||||
url(r'^roles/$', EnrollmentUserRolesView.as_view(), name='roles'),
|
||||
|
||||
@@ -7,8 +7,6 @@ consist primarily of authentication, request validation, and serialization.
|
||||
|
||||
import logging
|
||||
|
||||
from six import text_type
|
||||
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from django.utils.decorators import method_decorator # lint-amnesty, pylint: disable=wrong-import-order
|
||||
@@ -62,7 +60,7 @@ class EnrollmentCrossDomainSessionAuth(SessionAuthenticationAllowInactiveUser, S
|
||||
pass # lint-amnesty, pylint: disable=unnecessary-pass
|
||||
|
||||
|
||||
class ApiKeyPermissionMixIn(object):
|
||||
class ApiKeyPermissionMixIn:
|
||||
"""
|
||||
This mixin is used to provide a convenience function for doing individual permission checks
|
||||
for the presence of API keys.
|
||||
@@ -99,7 +97,7 @@ class EnrollmentUserThrottle(UserRateThrottle, ApiKeyPermissionMixIn):
|
||||
self.rate = self.get_rate()
|
||||
self.num_requests, self.duration = self.parse_rate(self.rate)
|
||||
|
||||
return self.has_api_key_permissions(request) or super(EnrollmentUserThrottle, self).allow_request(request, view) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
return self.has_api_key_permissions(request) or super().allow_request(request, view)
|
||||
|
||||
|
||||
@can_disable_rate_limit
|
||||
@@ -210,8 +208,8 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn):
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": (
|
||||
u"An error occurred while retrieving enrollments for user "
|
||||
u"'{username}' in course '{course_id}'"
|
||||
"An error occurred while retrieving enrollments for user "
|
||||
"'{username}' in course '{course_id}'"
|
||||
).format(username=username, course_id=course_id)
|
||||
}
|
||||
)
|
||||
@@ -258,13 +256,13 @@ class EnrollmentUserRolesView(APIView):
|
||||
course_id = request.GET.get('course_id')
|
||||
roles_data = api.get_user_roles(request.user.username)
|
||||
if course_id:
|
||||
roles_data = [role for role in roles_data if text_type(role.course_id) == course_id]
|
||||
roles_data = [role for role in roles_data if str(role.course_id) == course_id]
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": (
|
||||
u"An error occurred while retrieving roles for user '{username}"
|
||||
"An error occurred while retrieving roles for user '{username}"
|
||||
).format(username=request.user.username)
|
||||
}
|
||||
)
|
||||
@@ -272,7 +270,7 @@ class EnrollmentUserRolesView(APIView):
|
||||
'roles': [
|
||||
{
|
||||
"org": role.org,
|
||||
"course_id": text_type(role.course_id),
|
||||
"course_id": str(role.course_id),
|
||||
"role": role.role
|
||||
}
|
||||
for role in roles_data],
|
||||
@@ -370,7 +368,7 @@ class EnrollmentCourseDetailView(APIView):
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": (
|
||||
u"No course found for course ID '{course_id}'"
|
||||
"No course found for course ID '{course_id}'"
|
||||
).format(course_id=course_id)
|
||||
}
|
||||
)
|
||||
@@ -429,11 +427,11 @@ class UnenrollmentView(APIView):
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
return Response(api.unenroll_user_from_all_courses(username))
|
||||
except KeyError:
|
||||
return Response(u'Username not specified.', status=status.HTTP_404_NOT_FOUND)
|
||||
return Response('Username not specified.', status=status.HTTP_404_NOT_FOUND)
|
||||
except UserRetirementStatus.DoesNotExist:
|
||||
return Response(u'No retirement request status for username.', status=status.HTTP_404_NOT_FOUND)
|
||||
return Response('No retirement request status for username.', status=status.HTTP_404_NOT_FOUND)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
return Response(str(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
||||
@can_disable_rate_limit
|
||||
@@ -647,7 +645,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": (
|
||||
u"An error occurred while retrieving enrollments for user '{username}'"
|
||||
"An error occurred while retrieving enrollments for user '{username}'"
|
||||
).format(username=username)
|
||||
}
|
||||
)
|
||||
@@ -676,7 +674,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
if not course_id:
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={"message": u"Course ID must be specified to create a new enrollment."}
|
||||
data={"message": "Course ID must be specified to create a new enrollment."}
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -685,7 +683,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": u"No course '{course_id}' found for enrollment".format(course_id=course_id)
|
||||
"message": f"No course '{course_id}' found for enrollment"
|
||||
}
|
||||
)
|
||||
|
||||
@@ -707,7 +705,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
return Response(
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
data={
|
||||
"message": u"User does not have permission to create enrollment with mode [{mode}].".format(
|
||||
"message": "User does not have permission to create enrollment with mode [{mode}].".format(
|
||||
mode=mode
|
||||
)
|
||||
}
|
||||
@@ -720,7 +718,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
return Response(
|
||||
status=status.HTTP_406_NOT_ACCEPTABLE,
|
||||
data={
|
||||
'message': u'The user {} does not exist.'.format(username)
|
||||
'message': f'The user {username} does not exist.'
|
||||
}
|
||||
)
|
||||
|
||||
@@ -736,7 +734,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
'message': (u"'{value}' is an invalid enrollment activation status.").format(value=is_active)
|
||||
'message': ("'{value}' is an invalid enrollment activation status.").format(value=is_active)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -745,26 +743,26 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
enterprise_api_client = EnterpriseApiServiceClient()
|
||||
consent_client = ConsentApiServiceClient()
|
||||
try:
|
||||
enterprise_api_client.post_enterprise_course_enrollment(username, text_type(course_id), None)
|
||||
enterprise_api_client.post_enterprise_course_enrollment(username, str(course_id), None)
|
||||
except EnterpriseApiException as error:
|
||||
log.exception(u"An unexpected error occurred while creating the new EnterpriseCourseEnrollment "
|
||||
u"for user [%s] in course run [%s]", username, course_id)
|
||||
raise CourseEnrollmentError(text_type(error)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
log.exception("An unexpected error occurred while creating the new EnterpriseCourseEnrollment "
|
||||
"for user [%s] in course run [%s]", username, course_id)
|
||||
raise CourseEnrollmentError(str(error)) # lint-amnesty, pylint: disable=raise-missing-from
|
||||
kwargs = {
|
||||
'username': username,
|
||||
'course_id': text_type(course_id),
|
||||
'course_id': str(course_id),
|
||||
'enterprise_customer_uuid': explicit_linked_enterprise,
|
||||
}
|
||||
consent_client.provide_consent(**kwargs)
|
||||
|
||||
enrollment_attributes = request.data.get('enrollment_attributes')
|
||||
enrollment = api.get_enrollment(username, text_type(course_id))
|
||||
enrollment = api.get_enrollment(username, str(course_id))
|
||||
mode_changed = enrollment and mode is not None and enrollment['mode'] != mode
|
||||
active_changed = enrollment and is_active is not None and enrollment['is_active'] != is_active
|
||||
missing_attrs = []
|
||||
if enrollment_attributes:
|
||||
actual_attrs = [
|
||||
u"{namespace}:{name}".format(**attr)
|
||||
"{namespace}:{name}".format(**attr)
|
||||
for attr in enrollment_attributes
|
||||
]
|
||||
missing_attrs = set(REQUIRED_ATTRIBUTES.get(mode, [])) - set(actual_attrs)
|
||||
@@ -773,14 +771,14 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
# if the requester wanted to deactivate but specified the wrong mode, fail
|
||||
# the request (on the assumption that the requester had outdated information
|
||||
# about the currently active enrollment).
|
||||
msg = u"Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate.".format(
|
||||
msg = "Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate.".format(
|
||||
enrollment["mode"], mode
|
||||
)
|
||||
log.warning(msg)
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST, data={"message": msg})
|
||||
|
||||
if missing_attrs:
|
||||
msg = u"Missing enrollment attributes: requested mode={} required attributes={}".format(
|
||||
msg = "Missing enrollment attributes: requested mode={} required attributes={}".format(
|
||||
mode, REQUIRED_ATTRIBUTES.get(mode)
|
||||
)
|
||||
log.warning(msg)
|
||||
@@ -788,7 +786,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
|
||||
response = api.update_enrollment(
|
||||
username,
|
||||
text_type(course_id),
|
||||
str(course_id),
|
||||
mode=mode,
|
||||
is_active=is_active,
|
||||
enrollment_attributes=enrollment_attributes,
|
||||
@@ -799,7 +797,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
# Will reactivate inactive enrollments.
|
||||
response = api.add_enrollment(
|
||||
username,
|
||||
text_type(course_id),
|
||||
str(course_id),
|
||||
mode=mode,
|
||||
is_active=is_active,
|
||||
enrollment_attributes=enrollment_attributes
|
||||
@@ -818,14 +816,14 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
org = course_id.org
|
||||
update_email_opt_in(request.user, org, email_opt_in)
|
||||
|
||||
log.info(u'The user [%s] has already been enrolled in course run [%s].', username, course_id)
|
||||
log.info('The user [%s] has already been enrolled in course run [%s].', username, course_id)
|
||||
return Response(response)
|
||||
except CourseModeNotFoundError as error:
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": (
|
||||
u"The [{mode}] course mode is expired or otherwise unavailable for course run [{course_id}]."
|
||||
"The [{mode}] course mode is expired or otherwise unavailable for course run [{course_id}]."
|
||||
).format(mode=mode, course_id=course_id),
|
||||
"course_details": error.data
|
||||
})
|
||||
@@ -833,38 +831,38 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": u"No course '{course_id}' found for enrollment".format(course_id=course_id)
|
||||
"message": f"No course '{course_id}' found for enrollment"
|
||||
}
|
||||
)
|
||||
except CourseEnrollmentExistsError as error:
|
||||
log.warning(u'An enrollment already exists for user [%s] in course run [%s].', username, course_id)
|
||||
log.warning('An enrollment already exists for user [%s] in course run [%s].', username, course_id)
|
||||
return Response(data=error.enrollment)
|
||||
except CourseEnrollmentError:
|
||||
log.exception(u"An error occurred while creating the new course enrollment for user "
|
||||
u"[%s] in course run [%s]", username, course_id)
|
||||
log.exception("An error occurred while creating the new course enrollment for user "
|
||||
"[%s] in course run [%s]", username, course_id)
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": (
|
||||
u"An error occurred while creating the new course enrollment for user "
|
||||
u"'{username}' in course '{course_id}'"
|
||||
"An error occurred while creating the new course enrollment for user "
|
||||
"'{username}' in course '{course_id}'"
|
||||
).format(username=username, course_id=course_id)
|
||||
}
|
||||
)
|
||||
except CourseUserGroup.DoesNotExist:
|
||||
log.exception(u'Missing cohort [%s] in course run [%s]', cohort_name, course_id)
|
||||
log.exception('Missing cohort [%s] in course run [%s]', cohort_name, course_id)
|
||||
return Response(
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
data={
|
||||
"message": u"An error occured while adding to cohort [%s]" % cohort_name
|
||||
"message": "An error occured while adding to cohort [%s]" % cohort_name
|
||||
})
|
||||
finally:
|
||||
# Assumes that the ecommerce service uses an API key to authenticate.
|
||||
if has_api_key_permissions:
|
||||
current_enrollment = api.get_enrollment(username, text_type(course_id))
|
||||
current_enrollment = api.get_enrollment(username, str(course_id))
|
||||
audit_log(
|
||||
'enrollment_change_requested',
|
||||
course_id=text_type(course_id),
|
||||
course_id=str(course_id),
|
||||
requested_mode=mode,
|
||||
actual_mode=current_enrollment['mode'] if current_enrollment else None,
|
||||
requested_activation=is_active,
|
||||
|
||||
Reference in New Issue
Block a user