feat: Update cert_generation mgmt command with ability to read arguments from config model

[MICROBA-1100]
* Add CertificationGenerationCommandConfiguration model that will store the command arguments for the `cert_generation` mgmt command
* Add ability to add entries to the CertificationGenerationCommandConfiguration through Django admin
* Update mgmt command with ability to read arguments from the config model/database
* Fix failing test in `test_cert_generation.py`
* Add new test for missing `users` argument in `test_cert_generation.py`
This commit is contained in:
Justin Hynes
2021-03-31 09:51:28 -04:00
parent 5025a3ffd9
commit 6b38debfeb
5 changed files with 94 additions and 5 deletions

View File

@@ -15,6 +15,7 @@ from organizations.api import get_organizations
from lms.djangoapps.certificates.models import (
AllowListGenerationConfiguration,
CertificateGenerationConfiguration,
CertificateGenerationCommandConfiguration,
CertificateGenerationCourseSetting,
CertificateHtmlViewConfiguration,
CertificateTemplate,
@@ -95,6 +96,11 @@ class CertificateGenerationCourseSettingAdmin(admin.ModelAdmin):
class AllowListGenerationConfigurationAdmin(ConfigurationModelAdmin):
pass
@admin.register(CertificateGenerationCommandConfiguration)
class CertificateGenerationCommandConfigurationAdmin(ConfigurationModelAdmin):
pass
admin.site.register(CertificateGenerationConfiguration)
admin.site.register(CertificateGenerationCourseSetting, CertificateGenerationCourseSettingAdmin)
admin.site.register(CertificateHtmlViewConfiguration, ConfigurationModelAdmin)

View File

@@ -3,6 +3,7 @@ Management command to generate course certificates for one or more users in a gi
"""
import logging
import shlex
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand, CommandError
@@ -10,6 +11,7 @@ from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from lms.djangoapps.certificates.generation_handler import generate_certificate_task
from lms.djangoapps.certificates.models import CertificateGenerationCommandConfiguration
User = get_user_model()
log = logging.getLogger(__name__)
@@ -33,18 +35,40 @@ class Command(BaseCommand):
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'
)
parser.add_argument(
'--args-from-database',
action='store_true',
help='Use arguments from the CertificateGenerationCommandConfiguration model instead of the command line'
)
def get_args_from_database(self):
"""
Returns an options dictionary from the current CertificateGenerationCommandConfiguration model.
"""
config = CertificateGenerationCommandConfiguration.current()
if not config.enabled:
raise CommandError(
"CertificateGenerationCommandConfiguration is disabled, but --args-from-database was requested"
)
args = shlex.split(config.arguments)
parser = self.create_parser("manage.py", "cert_generation")
return vars(parser.parse_args(args))
def handle(self, *args, **options):
# database args will override cmd line args
if options['args_from_database']:
options = self.get_args_from_database()
if not options.get('user'):
raise CommandError('You must specify a list of users')

View File

@@ -43,13 +43,20 @@ class CertGenerationTests(ModuleStoreTestCase):
mode="verified",
)
def test_command_with_missing_param(self):
def test_command_with_missing_param_course_key(self):
"""
Verify command with a missing param
Verify command with a missing param -- course key.
"""
with pytest.raises(CommandError, match="Error: the following arguments are required"):
with pytest.raises(CommandError, match="You must specify a course-key"):
call_command("cert_generation", "--u", self.user.username)
def test_command_with_missing_param_users(self):
"""
Verify command with a missing param -- users.
"""
with pytest.raises(CommandError, match="You must specify a list of users"):
call_command("cert_generation", "--c", "blah")
def test_command_with_invalid_key(self):
"""
Verify command with an invalid course run key

View File

@@ -0,0 +1,29 @@
# Generated by Django 2.2.19 on 2021-03-30 19:37
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('certificates', '0022_add_unique_constraints_to_certificatewhitelist_model'),
]
operations = [
migrations.CreateModel(
name='CertificateGenerationCommandConfiguration',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
('arguments', models.TextField(blank=True, default='', help_text="Arguments for the 'cert_generation' management command. Specify like '-u <user_id> -c <course_run_key>'")),
('changed_by', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Changed by')),
],
options={
'verbose_name': 'cert_generation argument',
},
),
]

View File

@@ -1245,3 +1245,26 @@ class AllowListGenerationConfiguration(ConfigurationModel):
def __str__(self):
return str(self.arguments)
class CertificateGenerationCommandConfiguration(ConfigurationModel):
"""
Manages configuration for a run of the cert_generation management command.
.. no_pii:
"""
class Meta(object):
app_label = "certificates"
verbose_name = "cert_generation argument"
arguments = models.TextField(
blank=True,
help_text=(
"Arguments for the 'cert_generation' management command. Specify like '-u <user_id> -c <course_run_key>'"
),
default="",
)
def __str__(self):
return str(self.arguments)