feat: Allow cert allowlist mgmt cmd to use db args

The management command to generate certificates for users on a course's
allowlist (formerly whitelist) now allows for database arguments to
allow it to be called outside of a manual shell.
This commit is contained in:
Matt Tuchfarber
2021-02-16 14:49:26 -05:00
parent 7840c1f248
commit d380d85f5c
5 changed files with 82 additions and 4 deletions

View File

@@ -13,6 +13,7 @@ from django.utils.safestring import mark_safe
from organizations.api import get_organizations
from lms.djangoapps.certificates.models import (
AllowListGenerationConfiguration,
CertificateGenerationConfiguration,
CertificateGenerationCourseSetting,
CertificateHtmlViewConfiguration,
@@ -90,6 +91,10 @@ class CertificateGenerationCourseSettingAdmin(admin.ModelAdmin):
show_full_result_count = False
@admin.register(AllowListGenerationConfiguration)
class AllowListGenerationConfigurationAdmin(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 allowlist certificates for one or more users in a
"""
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_allowlist_certificate_task
from lms.djangoapps.certificates.models import AllowListGenerationConfiguration
User = get_user_model()
log = logging.getLogger(__name__)
@@ -33,23 +35,44 @@ class Command(BaseCommand):
nargs="+",
metavar='USER',
dest='user',
required=True,
help='user or space-separated list of users for whom to generate allowlist 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 AllowListGenerationConfiguration model instead of the command line.',
)
def get_args_from_database(self):
""" Returns an options dictionary from the current AllowListGenerationConfiguration model. """
config = AllowListGenerationConfiguration.current()
if not config.enabled:
raise CommandError("AllowListGenerationConfiguration is disabled, but --args-from-database was requested.")
argv = shlex.split(config.arguments)
parser = self.create_parser("manage.py", "cert_allowlist_generation")
return vars(parser.parse_args(argv)) # we want a dictionary, not a non-iterable Namespace object
def handle(self, *args, **options):
# Parse the serialized course key into a CourseKey
# database args will override cmd line args
if options['args_from_database']:
options = self.get_args_from_database()
# Since we're optionally using database args we can't simply make users required in the arguments
if not options["user"]:
raise CommandError("You must specify a list of users")
course_key = options['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:

View File

@@ -57,7 +57,7 @@ class CertAllowlistGenerationTests(ModuleStoreTestCase):
"""
Verify command with a missing param
"""
with pytest.raises(CommandError, match="Error: the following arguments are required: -c/--course-key"):
with pytest.raises(CommandError, match="You must specify a course-key"):
call_command("cert_allowlist_generation", "--u", self.user.username)
def test_command_with_invalid_key(self):

View File

@@ -0,0 +1,29 @@
# Generated by Django 2.2.18 on 2021-02-16 18:12
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', '0018_historicalcertificateinvalidation'),
]
operations = [
migrations.CreateModel(
name='AllowListGenerationConfiguration',
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='Useful for manually running a Jenkins job. Specify like "-u edx verified -c course-v1:edX+DemoX+Demo_Course."')),
('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_allowlist_generation argument',
},
),
]

View File

@@ -1259,3 +1259,24 @@ def create_course_group_badge(sender, user, course_key, status, **kwargs): # py
Standard signal hook to create badges when a user has completed a prespecified set of courses.
"""
course_group_check(user, course_key)
class AllowListGenerationConfiguration(ConfigurationModel):
"""
Manages configuration for a run of the cert_allowlist_generation management command.
.. no_pii:
"""
class Meta(object):
app_label = 'certificates'
verbose_name = 'cert_allowlist_generation argument'
arguments = models.TextField(
blank=True,
help_text='Useful for manually running a Jenkins job. Specify like "-u edx verified -c course-v1:edX+DemoX+Demo_Course."',
default='',
)
def __str__(self):
return str(self.arguments)