Let notify_credentials get args from db
To allow the notify_credentials management command to run from a jenkins job, we want to allow the command to pull its arguments from the database, rather than the jenkins interface. So this adds a table that admins can adjust in the DB and a new argument for notify_credentials to tell it to go look there. LEARNER-6196 LEARNER-6197
This commit is contained in:
committed by
Michael Terry
parent
f022e98971
commit
6f7b19b6bf
@@ -5,11 +5,14 @@ Django admin pages for credentials support models.
|
||||
from config_models.admin import ConfigurationModelAdmin
|
||||
from django.contrib import admin
|
||||
|
||||
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig
|
||||
from openedx.core.djangoapps.credentials.models import CredentialsApiConfig, NotifyCredentialsConfig
|
||||
|
||||
|
||||
@admin.register(CredentialsApiConfig)
|
||||
class CredentialsApiConfigAdmin(ConfigurationModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
admin.site.register(CredentialsApiConfig, CredentialsApiConfigAdmin)
|
||||
@admin.register(NotifyCredentialsConfig)
|
||||
class NotifyCredentialsConfigAdmin(ConfigurationModelAdmin):
|
||||
pass
|
||||
|
||||
@@ -24,6 +24,7 @@ from pytz import UTC
|
||||
|
||||
from lms.djangoapps.certificates.models import GeneratedCertificate
|
||||
from lms.djangoapps.grades.models import PersistentCourseGrade
|
||||
from openedx.core.djangoapps.credentials.models import NotifyCredentialsConfig
|
||||
from openedx.core.djangoapps.credentials.signals import handle_cert_change, send_grade_if_interesting
|
||||
from openedx.core.djangoapps.programs.signals import handle_course_cert_changed
|
||||
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
|
||||
@@ -134,8 +135,28 @@ class Command(BaseCommand):
|
||||
default=100,
|
||||
help="Number of items to query at once.",
|
||||
)
|
||||
parser.add_argument(
|
||||
'--args-from-database',
|
||||
action='store_true',
|
||||
help='Use arguments from the NotifyCredentialsConfig model instead of the command line.',
|
||||
)
|
||||
|
||||
def get_args_from_database(self):
|
||||
""" Returns an options dictionary from the current NotifyCredentialsConfig model. """
|
||||
config = NotifyCredentialsConfig.current()
|
||||
if not config.enabled:
|
||||
raise CommandError('NotifyCredentialsConfig is disabled, but --args-from-database was requested.')
|
||||
|
||||
# We don't need fancy shell-style whitespace/quote handling - none of our arguments are complicated
|
||||
argv = config.arguments.split()
|
||||
|
||||
parser = self.create_parser('manage.py', 'notify_credentials')
|
||||
return parser.parse_args(argv).__dict__ # we want a dictionary, not a non-iterable Namespace object
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if options['args_from_database']:
|
||||
options = self.get_args_from_database()
|
||||
|
||||
log.info(
|
||||
"notify_credentials starting, dry-run=%s, site=%s, delay=%d seconds",
|
||||
options['dry_run'],
|
||||
|
||||
@@ -14,6 +14,7 @@ from freezegun import freeze_time
|
||||
|
||||
from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory
|
||||
from lms.djangoapps.grades.models import PersistentCourseGrade
|
||||
from openedx.core.djangoapps.credentials.models import NotifyCredentialsConfig
|
||||
from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
from student.tests.factories import UserFactory
|
||||
@@ -131,3 +132,30 @@ class TestNotifyCredentials(TestCase):
|
||||
call_command(Command(), '--site', site_config.site.domain, '--start-date', '2017-01-01')
|
||||
self.assertEqual(mock_grade_interesting.call_count, 1)
|
||||
self.assertEqual(mock_cert_change.call_count, 1)
|
||||
|
||||
@mock.patch(COMMAND_MODULE + '.Command.send_notifications')
|
||||
def test_args_from_database(self, mock_send):
|
||||
# Nothing in the database, should default to disabled
|
||||
with self.assertRaisesRegex(CommandError, 'NotifyCredentialsConfig is disabled.*'):
|
||||
call_command(Command(), '--start-date', '2017-01-01', '--args-from-database')
|
||||
|
||||
# Add a config
|
||||
config = NotifyCredentialsConfig.current()
|
||||
config.arguments = '--start-date 2017-03-01'
|
||||
config.enabled = True
|
||||
config.save()
|
||||
|
||||
# Not told to use config, should ignore it
|
||||
call_command(Command(), '--start-date', '2017-01-01')
|
||||
self.assertEqual(len(mock_send.call_args[0][0]), 3)
|
||||
|
||||
# Told to use it, and enabled. Should use config in preference of command line
|
||||
call_command(Command(), '--start-date', '2017-01-01', '--args-from-database')
|
||||
self.assertEqual(len(mock_send.call_args[0][0]), 1)
|
||||
|
||||
config.enabled = False
|
||||
config.save()
|
||||
|
||||
# Explicitly disabled
|
||||
with self.assertRaisesRegex(CommandError, 'NotifyCredentialsConfig is disabled.*'):
|
||||
call_command(Command(), '--start-date', '2017-01-01', '--args-from-database')
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.15 on 2018-08-17 18:14
|
||||
from __future__ import unicode_literals
|
||||
|
||||
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),
|
||||
('credentials', '0003_auto_20170525_1109'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NotifyCredentialsConfig',
|
||||
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 "--start-date=2018 --courses A B".')),
|
||||
('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': 'notify_credentials argument',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -108,3 +108,22 @@ class CredentialsApiConfig(ConfigurationModel):
|
||||
def is_cache_enabled(self):
|
||||
"""Whether responses from the Credentials API will be cached."""
|
||||
return self.cache_ttl > 0
|
||||
|
||||
|
||||
class NotifyCredentialsConfig(ConfigurationModel):
|
||||
"""
|
||||
Manages configuration for a run of the notify_credentials management command.
|
||||
"""
|
||||
|
||||
class Meta(object):
|
||||
app_label = 'credentials'
|
||||
verbose_name = 'notify_credentials argument'
|
||||
|
||||
arguments = models.TextField(
|
||||
blank=True,
|
||||
help_text='Useful for manually running a Jenkins job. Specify like "--start-date=2018 --courses A B".',
|
||||
default='',
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.arguments)
|
||||
|
||||
Reference in New Issue
Block a user