Merge pull request #26989 from edx/jhynes/microba-1011_allowlist-uniqueness

MICROBA-1011 | Remove duplicate allowlist entries and add constraint preventing future occurrences
This commit is contained in:
Justin Hynes
2021-03-15 09:15:20 -04:00
committed by GitHub
4 changed files with 78 additions and 2 deletions

View File

@@ -0,0 +1,36 @@
# Generated by Django 2.2.19 on 2021-03-11 19:31
from django.db import migrations
from django.db.models import Count, Min
class Migration(migrations.Migration):
"""
Delete all the duplicate records in the `CERTIFICATES_CERTIFICATEWHITELIST` table.
"""
def remove_duplicate_entries(apps, schema_editor):
CertificateWhitelist = apps.get_model('certificates', 'CertificateWhitelist')
allowlist_duplicates = (
CertificateWhitelist.objects.values("user_id", "course_id")
.annotate(first_entry_id=Min("id"), num_entries=Count("id"))
.filter(num_entries__gt=1)
)
# delete the duplicates, excluding the original allowlist entry for the user/course-run combo
for duplicate in allowlist_duplicates:
(
CertificateWhitelist.objects
.filter(user_id=duplicate["user_id"], course_id=duplicate["course_id"])
.exclude(id=duplicate["first_entry_id"])
.delete()
)
dependencies = [
('certificates', '0020_remove_existing_mgmt_cmd_args'),
]
operations = [
migrations.RunPython(remove_duplicate_entries, reverse_code=migrations.RunPython.noop)
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 2.2.19 on 2021-03-12 17:27
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('certificates', '0021_remove_certificate_allowlist_duplicate_records'),
]
operations = [
migrations.AlterUniqueTogether(
name='certificatewhitelist',
unique_together={('course_id', 'user')},
),
]

View File

@@ -97,6 +97,7 @@ class CertificateWhitelist(models.Model):
"""
class Meta:
app_label = "certificates"
unique_together = [['course_id', 'user']]
objects = NoneToEmptyManager()

View File

@@ -81,7 +81,7 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase):
mode="verified",
)
def test_cert_generation_on_whitelist_append_self_paced(self):
def test_cert_generation_on_allowlist_append_self_paced_auto_cert_generation_disabled(self):
"""
Verify that signal is sent, received, and fires task
based on 'AUTO_CERTIFICATE_GENERATION' flag
@@ -96,6 +96,16 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase):
course_id=self.course.id
)
mock_generate_certificate_apply_async.assert_not_called()
def test_cert_generation_on_allowlist_append_self_paced_auto_cert_generation_enabled(self):
"""
Verify that signal is sent, received, and fires task
based on 'AUTO_CERTIFICATE_GENERATION' flag
"""
with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None
) as mock_generate_certificate_apply_async:
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION_SWITCH, active=True):
CertificateWhitelistFactory(
user=self.user,
@@ -109,7 +119,7 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase):
}
)
def test_cert_generation_on_whitelist_append_instructor_paced(self):
def test_cert_generation_on_allowlist_append_instructor_paced_cert_generation_disabled(self):
"""
Verify that signal is sent, received, and fires task
based on 'AUTO_CERTIFICATE_GENERATION' flag
@@ -124,6 +134,16 @@ class WhitelistGeneratedCertificatesTest(ModuleStoreTestCase):
course_id=self.ip_course.id
)
mock_generate_certificate_apply_async.assert_not_called()
def test_cert_generation_on_allowlist_append_instructor_paced_cert_generation_enabled(self):
"""
Verify that signal is sent, received, and fires task
based on 'AUTO_CERTIFICATE_GENERATION' flag
"""
with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None
) as mock_generate_certificate_apply_async:
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION_SWITCH, active=True):
CertificateWhitelistFactory(
user=self.user,