From 22f8b6522803793ca28d3ce0abf5db17117fd600 Mon Sep 17 00:00:00 2001 From: Troy Sankey Date: Tue, 10 Dec 2019 13:08:52 -0500 Subject: [PATCH] Add history to GeneratedCertificate DE-1881 --- .../0016_historicalgeneratedcertificate.py | 51 +++++++++++++++++++ lms/djangoapps/certificates/models.py | 8 +++ .../tests/test_tasks_helper.py | 2 +- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 lms/djangoapps/certificates/migrations/0016_historicalgeneratedcertificate.py diff --git a/lms/djangoapps/certificates/migrations/0016_historicalgeneratedcertificate.py b/lms/djangoapps/certificates/migrations/0016_historicalgeneratedcertificate.py new file mode 100644 index 0000000000..80261cb07a --- /dev/null +++ b/lms/djangoapps/certificates/migrations/0016_historicalgeneratedcertificate.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.26 on 2019-12-10 18:05 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import opaque_keys.edx.django.models +import simple_history.models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('certificates', '0015_add_masters_choice'), + ] + + operations = [ + migrations.CreateModel( + name='HistoricalGeneratedCertificate', + fields=[ + ('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')), + ('course_id', opaque_keys.edx.django.models.CourseKeyField(blank=True, default=None, max_length=255)), + ('verify_uuid', models.CharField(blank=True, db_index=True, default='', max_length=32)), + ('download_uuid', models.CharField(blank=True, default='', max_length=32)), + ('download_url', models.CharField(blank=True, default='', max_length=128)), + ('grade', models.CharField(blank=True, default='', max_length=5)), + ('key', models.CharField(blank=True, default='', max_length=32)), + ('distinction', models.BooleanField(default=False)), + ('status', models.CharField(default='unavailable', max_length=32)), + ('mode', models.CharField(choices=[('verified', 'verified'), ('honor', 'honor'), ('audit', 'audit'), ('professional', 'professional'), ('no-id-professional', 'no-id-professional'), ('masters', 'masters')], default='honor', max_length=32)), + ('name', models.CharField(blank=True, max_length=255)), + ('created_date', models.DateTimeField(blank=True, editable=False)), + ('modified_date', models.DateTimeField(blank=True, editable=False)), + ('error_reason', models.CharField(blank=True, default='', max_length=512)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField()), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ('-history_date', '-history_id'), + 'verbose_name': 'historical generated certificate', + 'get_latest_by': 'history_date', + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + ] diff --git a/lms/djangoapps/certificates/models.py b/lms/djangoapps/certificates/models.py index e7ee233246..d337e6e863 100644 --- a/lms/djangoapps/certificates/models.py +++ b/lms/djangoapps/certificates/models.py @@ -54,6 +54,7 @@ import uuid import six from config_models.models import ConfigurationModel +from django.apps import apps from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ValidationError @@ -66,6 +67,7 @@ from model_utils import Choices from model_utils.fields import AutoCreatedField from model_utils.models import TimeStampedModel from opaque_keys.edx.django.models import CourseKeyField +from simple_history.models import HistoricalRecords from badges.events.course_complete import course_badge_check from badges.events.course_meta import completion_check, course_group_check @@ -280,6 +282,12 @@ class GeneratedCertificate(models.Model): modified_date = models.DateTimeField(auto_now=True) error_reason = models.CharField(max_length=512, blank=True, default='') + # This is necessary because CMS does not install the certificates app, but it + # imports this models code. Simple History will attempt to connect to the installed + # model in the certificates app, which will fail. + if 'certificates' in apps.app_configs: + history = HistoricalRecords() + class Meta(object): unique_together = (('user', 'course_id'),) app_label = "certificates" diff --git a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py index 4778b6be2b..60f804af6a 100644 --- a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py +++ b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py @@ -2268,7 +2268,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase): 'failed': 3, 'skipped': 2 } - with self.assertNumQueries(130): + with self.assertNumQueries(146): self.assertCertificatesGenerated(task_input, expected_results) expected_results = {