Revert "Revert "Create Python API for program_enrollments: Part IV"" (#21759)

This reverts commit a67b9f70a16a0f16a842aad84754b245a2480b5f,
reinstating commit cf78660ed35712f9bb7c112f70411179070d7382.
The original commit was reverted because I thought I found
bugs in it while verifying it on Stage, but it turns out that
it was simply misconfigured Stage data that causing errors.

The original commit's message has has been copied below:

This commit completes the program_enrollments LMS app
Python API for the time being. It does the following:
* Add bulk-lookup of users by external key in api/reading.py
* Add bulk-writing of program enrollments in api/writing.py
* Move grade-reading to api/grades.py
* Refactor api/linking.py to use api/writing.py
* Refactor signals.py to use api/linking.py
* Update rest_api/v1/views.py to utilize all these changes
* Update linking management command and support tool to use API
* Remove outdated tests from test_models.py
* Misc. cleanup

EDUCATOR-4321
This commit is contained in:
Kyle McCormick
2019-09-24 10:49:54 -04:00
committed by GitHub
parent 76d7270fe9
commit da08357d89
27 changed files with 1581 additions and 1393 deletions

View File

@@ -15,11 +15,10 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou
from student.tests.factories import UserFactory
from ..linking import (
COURSE_ENROLLMENT_ERR_TEMPLATE,
NO_LMS_USER_TEMPLATE,
NO_PROGRAM_ENROLLMENT_TEMPLATE,
link_program_enrollments_to_lms_users,
user_already_linked_message
_user_already_linked_message,
link_program_enrollments
)
LOG_PATH = 'lms.djangoapps.program_enrollments.api.linking'
@@ -123,15 +122,6 @@ class TestLinkProgramEnrollmentsMixin(object):
[course_enrollment.course.id for course_enrollment in course_enrollments]
)
def _assert_error_message(self, errors, error_key, logger, log_level, expected_error_msg):
logger.check_present((LOG_PATH, log_level, expected_error_msg))
self.assertDictEqual(
{
error_key: expected_error_msg
},
errors
)
class TestLinkProgramEnrollments(TestLinkProgramEnrollmentsMixin, TestCase):
""" Tests for linking behavior """
@@ -149,7 +139,7 @@ class TestLinkProgramEnrollments(TestLinkProgramEnrollmentsMixin, TestCase):
self._create_waiting_course_enrollment(another_program_enrollment, self.fruit_course)
self._create_waiting_course_enrollment(another_program_enrollment, self.animal_course)
link_program_enrollments_to_lms_users(self.program, {'0001': self.user_1.username})
link_program_enrollments(self.program, {'0001': self.user_1.username})
self._assert_program_enrollment(self.user_1, self.program, '0001')
self._assert_user_enrolled_in_program_courses(
@@ -175,7 +165,7 @@ class TestLinkProgramEnrollments(TestLinkProgramEnrollmentsMixin, TestCase):
status='inactive'
)
link_program_enrollments_to_lms_users(self.program, {'0001': self.user_1.username})
link_program_enrollments(self.program, {'0001': self.user_1.username})
self._assert_program_enrollment(self.user_1, self.program, '0001')
@@ -209,7 +199,7 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
asserts that user_2 was not linked because the enrollment was not found
"""
with LogCapture() as logger:
errors = link_program_enrollments_to_lms_users(
errors = link_program_enrollments(
self.program,
{
'0001': self.user_1.username,
@@ -222,7 +212,7 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
)
logger.check_present((LOG_PATH, 'WARNING', expected_error_msg))
self.assertDictEqual(errors, {('0002', self.user_2.username): expected_error_msg})
self.assertDictEqual(errors, {'0002': expected_error_msg})
self._assert_program_enrollment(self.user_1, self.program, '0001')
self._assert_no_program_enrollment(self.user_2, self.program)
@@ -231,7 +221,7 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
enrollment_2 = self._create_waiting_enrollment(self.program, '0002')
with LogCapture() as logger:
errors = link_program_enrollments_to_lms_users(
errors = link_program_enrollments(
self.program,
{
'0001': self.user_1.username,
@@ -241,7 +231,7 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
expected_error_msg = NO_LMS_USER_TEMPLATE.format('nonexistant-user')
logger.check_present((LOG_PATH, 'WARNING', expected_error_msg))
self.assertDictEqual(errors, {('0002', 'nonexistant-user'): expected_error_msg})
self.assertDictEqual(errors, {'0002': expected_error_msg})
self._assert_program_enrollment(self.user_1, self.program, '0001')
self._assert_no_user(enrollment_2)
@@ -256,17 +246,17 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
self._assert_program_enrollment(self.user_2, self.program, '0002', refresh=False)
with LogCapture() as logger:
errors = link_program_enrollments_to_lms_users(
errors = link_program_enrollments(
self.program,
{
'0001': self.user_1.username,
'0002': self.user_2.username
}
)
expected_error_msg = user_already_linked_message(program_enrollment, self.user_2)
expected_error_msg = _user_already_linked_message(program_enrollment, self.user_2)
logger.check_present((LOG_PATH, 'WARNING', expected_error_msg))
self.assertDictEqual(errors, {('0002', self.user_2.username): expected_error_msg})
self.assertDictEqual(errors, {'0002': expected_error_msg})
self._assert_program_enrollment(self.user_1, self.program, '0001')
self._assert_program_enrollment(self.user_2, self.program, '0002')
@@ -283,17 +273,17 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
self._assert_program_enrollment(user_3, self.program, '0003', refresh=False)
with LogCapture() as logger:
errors = link_program_enrollments_to_lms_users(
errors = link_program_enrollments(
self.program,
{
'0001': self.user_1.username,
'0003': self.user_2.username,
}
)
expected_error_msg = user_already_linked_message(enrollment, self.user_2)
expected_error_msg = _user_already_linked_message(enrollment, self.user_2)
logger.check_present((LOG_PATH, 'WARNING', expected_error_msg))
self.assertDictEqual(errors, {('0003', self.user_2.username): expected_error_msg})
self.assertDictEqual(errors, {'0003': expected_error_msg})
self._assert_program_enrollment(self.user_1, self.program, '0001')
self._assert_no_program_enrollment(self.user_2, self.program)
self._assert_program_enrollment(user_3, self.program, '0003')
@@ -313,22 +303,14 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
self._create_waiting_course_enrollment(program_enrollment_2, self.fruit_course)
self._create_waiting_course_enrollment(program_enrollment_2, self.animal_course)
msg = COURSE_ENROLLMENT_ERR_TEMPLATE.format(
user=self.user_1.username, course=nonexistant_course
)
with LogCapture() as logger:
errors = link_program_enrollments_to_lms_users(
self.program,
{
'0001': self.user_1.username,
'0002': self.user_2.username
}
)
logger.check_present((LOG_PATH, 'ERROR', msg))
self.assertDictEqual(
errors, {('0001', self.user_1.username): 'NonExistentCourseError: ' + msg}
errors = link_program_enrollments(
self.program,
{
'0001': self.user_1.username,
'0002': self.user_2.username
}
)
self.assertIn(errors['0001'], 'NonExistentCourseError: ')
self._assert_no_program_enrollment(self.user_1, self.program)
self._assert_no_user(program_enrollment_1)
course_enrollment_1.refresh_from_db()
@@ -348,46 +330,15 @@ class TestLinkProgramEnrollmentsErrors(TestLinkProgramEnrollmentsMixin, TestCase
program_enrollment_1 = self._create_waiting_enrollment(self.program, '0001')
self._create_waiting_enrollment(self.program, '0002')
msg = 'Integrity error while linking program enrollments'
with LogCapture() as logger:
errors = link_program_enrollments_to_lms_users(
self.program,
{
'0001': self.user_1.username,
'0002': self.user_2.username,
}
)
logger.check_present((LOG_PATH, 'ERROR', msg))
errors = link_program_enrollments(
self.program,
{
'0001': self.user_1.username,
'0002': self.user_2.username,
}
)
self.assertEqual(len(errors), 1)
self.assertIn('UNIQUE constraint failed', errors[('0001', self.user_1.username)])
self.assertIn('UNIQUE constraint failed', errors['0001'])
self._assert_no_user(program_enrollment_1)
self._assert_program_enrollment(self.user_2, self.program, '0002')
def test_invalid_uuid(self):
self._create_waiting_enrollment(self.program, 'learner-0')
with self.assertRaisesMessage(ValueError, 'badly formed hexadecimal UUID string'):
link_program_enrollments_to_lms_users(
'notauuid::thisisntauuid',
{
'learner-0': self.user_1.username,
}
)
def test_None(self):
self._create_waiting_enrollment(self.program, 'learner-0')
msg = 'external_user_key or username cannot be None'
with self.assertRaisesMessage(ValueError, msg):
link_program_enrollments_to_lms_users(
self.program,
{
None: self.user_1.username,
}
)
with self.assertRaisesMessage(ValueError, msg):
link_program_enrollments_to_lms_users(
'notauuid::thisisntauuid',
{
'learner-0': None,
}
)