diff --git a/lms/djangoapps/certificates/management/commands/cert_allowlist_generation.py b/lms/djangoapps/certificates/management/commands/cert_allowlist_generation.py index 7843daaea511eed4650bf825ca4e6b8ceb8b93b7..3de9e2ad1cc33f79d436909753b7f62842cceda2 100644 --- a/lms/djangoapps/certificates/management/commands/cert_allowlist_generation.py +++ b/lms/djangoapps/certificates/management/commands/cert_allowlist_generation.py @@ -22,7 +22,7 @@ class Command(BaseCommand): Management command to generate allowlist certificates for one or more users in a given course run. Example usage: - ./manage.py lms cert_allowlist_generation -u 123 verified -c course-v1:edX+DemoX+Demo_Course + ./manage.py lms cert_allowlist_generation -u 123 456 -c course-v1:edX+DemoX+Demo_Course """ help = """ diff --git a/lms/djangoapps/certificates/management/commands/cert_generation.py b/lms/djangoapps/certificates/management/commands/cert_generation.py new file mode 100644 index 0000000000000000000000000000000000000000..1d0f8ecd3e8fd33c68aa482b7481b8a016bdf67b --- /dev/null +++ b/lms/djangoapps/certificates/management/commands/cert_generation.py @@ -0,0 +1,75 @@ +""" +Management command to generate course certificates for one or more users in a given course run. +""" + +import logging + +from django.contrib.auth import get_user_model +from django.core.management.base import BaseCommand, CommandError +from opaque_keys import InvalidKeyError +from opaque_keys.edx.keys import CourseKey + +from lms.djangoapps.certificates.generation_handler import generate_certificate_task + +User = get_user_model() +log = logging.getLogger(__name__) + + +class Command(BaseCommand): + """ + Management command to generate course certificates for one or more users in a given course run. + + Example usage: + ./manage.py lms cert_generation -u 123 456 -c course-v1:edX+DemoX+Demo_Course + """ + + help = """ + Generate course certificates for one or more users in a given course run. + """ + + def add_arguments(self, parser): + parser.add_argument( + '-u', '--user', + nargs='+', + metavar='USER', + dest='user', + required=True, + help='user_id or space-separated list of user_ids for whom to generate course certificates' + ) + parser.add_argument( + '-c', '--course-key', + metavar='COURSE_KEY', + dest='course_key', + required=True, + help='course run key' + ) + + def handle(self, *args, **options): + if not options.get('user'): + raise CommandError('You must specify a list of users') + + course_key = options.get('course_key') + if not course_key: + raise CommandError('You must specify a course-key') + + # Parse the serialized course key into a CourseKey + try: + course_key = CourseKey.from_string(course_key) + except InvalidKeyError as e: + raise CommandError('You must specify a valid course-key') from e + + # Loop over each user, and ask that a cert be generated for them + users_str = options['user'] + for user_id in users_str: + user = None + try: + user = User.objects.get(id=user_id) + except User.DoesNotExist: + log.warning('User {user} could not be found'.format(user=user_id)) + if user is not None: + log.info( + 'Calling generate_certificate_task for {user} : {course}'.format( + user=user.id, + course=course_key + )) + generate_certificate_task(user, course_key) diff --git a/lms/djangoapps/certificates/management/commands/tests/test_cert_allowlist_generation.py b/lms/djangoapps/certificates/management/commands/tests/test_cert_allowlist_generation.py index a2cd0bdd3999993f4584271d041e7ff63c40c530..a273bf4a334cfd97eeacd17738d02d027f4599bf 100644 --- a/lms/djangoapps/certificates/management/commands/tests/test_cert_allowlist_generation.py +++ b/lms/djangoapps/certificates/management/commands/tests/test_cert_allowlist_generation.py @@ -1,5 +1,5 @@ """ -Tests for the cert_allowlist command +Tests for the cert_allowlist_generation command """ from unittest import mock @@ -79,6 +79,6 @@ class CertAllowlistGenerationTests(ModuleStoreTestCase): "--u", self.user.id, self.user2.id, - "999999", # non-existant userid + "999999", # non-existent userid "--c", self.course_run_key) diff --git a/lms/djangoapps/certificates/management/commands/tests/test_cert_generation.py b/lms/djangoapps/certificates/management/commands/tests/test_cert_generation.py new file mode 100644 index 0000000000000000000000000000000000000000..5e1879fa534de8934377383cbf80cb8b214599c0 --- /dev/null +++ b/lms/djangoapps/certificates/management/commands/tests/test_cert_generation.py @@ -0,0 +1,76 @@ +""" +Tests for the cert_generation command +""" + +from unittest import mock + +import pytest +from django.core.management import CommandError, call_command +from waffle.testutils import override_switch + +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from lms.djangoapps.certificates.tests.test_generation_handler import AUTO_GENERATION_SWITCH_NAME, ID_VERIFIED_METHOD +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.factories import CourseFactory + + +@override_switch(AUTO_GENERATION_SWITCH_NAME, active=True) +@mock.patch(ID_VERIFIED_METHOD, mock.Mock(return_value=True)) +class CertGenerationTests(ModuleStoreTestCase): + """ + Tests for the cert_generation management command + """ + + def setUp(self): + super().setUp() + + # Create users, a course run, and enrollments + self.user = UserFactory() + self.course_run = CourseFactory() + self.course_run_key = self.course_run.id # pylint: disable=no-member + self.enrollment = CourseEnrollmentFactory( + user=self.user, + course_id=self.course_run_key, + is_active=True, + mode="verified", + ) + + self.user2 = UserFactory() + self.enrollment2 = CourseEnrollmentFactory( + user=self.user2, + course_id=self.course_run_key, + is_active=True, + mode="verified", + ) + + def test_command_with_missing_param(self): + """ + Verify command with a missing param + """ + with pytest.raises(CommandError, match="Error: the following arguments are required"): + call_command("cert_generation", "--u", self.user.username) + + def test_command_with_invalid_key(self): + """ + Verify command with an invalid course run key + """ + with pytest.raises(CommandError, match="You must specify a valid course-key"): + call_command("cert_generation", "--u", self.user.username, "--c", "blah") + + def test_successful_generation(self): + """ + Test generation for 1 user + """ + call_command("cert_generation", "--u", self.user.id, "--c", self.course_run_key) + + def test_successful_generation_multiple_users(self): + """ + Test generation for multiple user + """ + call_command("cert_generation", + "--u", + self.user.id, + self.user2.id, + "999999", # non-existent userid + "--c", + self.course_run_key)