diff --git a/common/djangoapps/enrollment/management/__init__.py b/common/djangoapps/enrollment/management/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/djangoapps/enrollment/management/commands/__init__.py b/common/djangoapps/enrollment/management/commands/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/djangoapps/enrollment/management/commands/enroll_user_in_course.py b/common/djangoapps/enrollment/management/commands/enroll_user_in_course.py new file mode 100644 index 0000000000..033ed26565 --- /dev/null +++ b/common/djangoapps/enrollment/management/commands/enroll_user_in_course.py @@ -0,0 +1,52 @@ +""" +Management command for enrolling a user into a course via the enrollment api +""" +from django.contrib.auth.models import User +from django.core.management.base import BaseCommand +from enrollment.data import CourseEnrollmentExistsError +from enrollment.api import add_enrollment + + +class Command(BaseCommand): + """ + Enroll a user into a course + """ + help = """ + This enrolls a user into a given course with the default mode (e.g., 'honor', 'audit', etc). + + User email and course ID are required. + + example: + # Enroll a user test@example.com into the demo course + manage.py ... enroll_user_in_course -e test@example.com -c edX/Open_DemoX/edx_demo_course + + This command can be run multiple times on the same user+course (i.e. it is idempotent). + """ + + def add_arguments(self, parser): + + parser.add_argument( + '-e', '--email', + nargs=1, + required=True, + help='Email for user' + ) + parser.add_argument( + '-c', '--course', + nargs=1, + required=True, + help='course ID to enroll the user in') + + def handle(self, *args, **options): + """ + Get and enroll a user in the given course. Mode is optional and defers to the enrollment API for defaults. + """ + email = options['email'][0] + course = options['course'][0] + + user = User.objects.get(email=email) + try: + add_enrollment(user.username, course) + except CourseEnrollmentExistsError: + # If the user is already enrolled in the course, do nothing. + pass diff --git a/common/djangoapps/enrollment/management/tests/__init__.py b/common/djangoapps/enrollment/management/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/djangoapps/enrollment/management/tests/test_enroll_user_in_course.py b/common/djangoapps/enrollment/management/tests/test_enroll_user_in_course.py new file mode 100644 index 0000000000..9f36019666 --- /dev/null +++ b/common/djangoapps/enrollment/management/tests/test_enroll_user_in_course.py @@ -0,0 +1,87 @@ +""" Test the change_enrollment command line script.""" + +import ddt +import unittest +from uuid import uuid4 + +from django.conf import settings +from django.core.management import call_command +from django.core.management.base import CommandError + +from enrollment.api import get_enrollment +from student.tests.factories import UserFactory + +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory + + +@ddt.ddt +@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') +class EnrollManagementCommandTest(SharedModuleStoreTestCase): + """ + Test the enroll_user_in_course management command + """ + + @classmethod + def setUpClass(cls): + super(EnrollManagementCommandTest, cls).setUpClass() + cls.course = CourseFactory.create(org='fooX', number='007') + + def setUp(self): + super(EnrollManagementCommandTest, self).setUp() + self.course_id = unicode(self.course.id) + self.username = 'ralph' + uuid4().hex + self.user_email = self.username + '@example.com' + + UserFactory(username=self.username, email=self.user_email) + + def test_enroll_user(self): + + command_args = [ + '--course', self.course_id, + '--email', self.user_email, + ] + + call_command( + 'enroll_user_in_course', + *command_args + ) + + user_enroll = get_enrollment(self.username, self.course_id) + self.assertTrue(user_enroll['is_active']) + + def test_enroll_user_twice(self): + """ + Ensures the command is idempotent. + """ + + command_args = [ + '--course', self.course_id, + '--email', self.user_email, + ] + + for _ in range(2): + call_command( + 'enroll_user_in_course', + *command_args + ) + + # Second run does not impact the first run (i.e., the + # user is still enrolled, no exception was raised, etc) + user_enroll = get_enrollment(self.username, self.course_id) + self.assertTrue(user_enroll['is_active']) + + @ddt.data(['--email', 'foo'], ['--course', 'bar'], ['--bad-param', 'baz']) + def test_not_enough_args(self, arg): + """ + When the command is missing certain arguments, it should + raise an exception + """ + + command_args = arg + + with self.assertRaises(CommandError): + call_command( + 'enroll_user_in_course', + *command_args + )