diff --git a/lms/djangoapps/bulk_email/admin.py b/lms/djangoapps/bulk_email/admin.py index 2599e5f334..ff2513585d 100644 --- a/lms/djangoapps/bulk_email/admin.py +++ b/lms/djangoapps/bulk_email/admin.py @@ -10,6 +10,7 @@ from lms.djangoapps.bulk_email.forms import CourseAuthorizationAdminForm, Course from lms.djangoapps.bulk_email.models import ( BulkEmailFlag, CourseAuthorization, + DisabledCourse, CourseEmail, CourseEmailTemplate, Optout @@ -88,8 +89,14 @@ To enable email for the course, check the "Email enabled" box, then click "Save" ) +class DisabledCourseAdmin(admin.ModelAdmin): + """Admin for disabling bulk email on a course-by-course basis""" + list_display = ('course_id', ) + + admin.site.register(CourseEmail, CourseEmailAdmin) admin.site.register(Optout, OptoutAdmin) admin.site.register(CourseEmailTemplate, CourseEmailTemplateAdmin) admin.site.register(CourseAuthorization, CourseAuthorizationAdmin) admin.site.register(BulkEmailFlag, ConfigurationModelAdmin) +admin.site.register(DisabledCourse, DisabledCourseAdmin) diff --git a/lms/djangoapps/bulk_email/migrations/0007_disabledcourse.py b/lms/djangoapps/bulk_email/migrations/0007_disabledcourse.py new file mode 100644 index 0000000000..5591fcaffc --- /dev/null +++ b/lms/djangoapps/bulk_email/migrations/0007_disabledcourse.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.9 on 2021-11-22 16:05 + +from django.db import migrations, models +import opaque_keys.edx.django.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bulk_email', '0006_course_mode_targets'), + ] + + operations = [ + migrations.CreateModel( + name='DisabledCourse', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('course_id', opaque_keys.edx.django.models.CourseKeyField(db_index=True, max_length=255, unique=True)), + ], + ), + ] diff --git a/lms/djangoapps/bulk_email/models.py b/lms/djangoapps/bulk_email/models.py index 62791721d8..852b79f23f 100644 --- a/lms/djangoapps/bulk_email/models.py +++ b/lms/djangoapps/bulk_email/models.py @@ -471,6 +471,28 @@ class CourseAuthorization(models.Model): return f"Course '{str(self.course_id)}': Instructor Email {not_en}Enabled" +class DisabledCourse(models.Model): + """ + Disable the bulk email feature for specific courses. + + .. no_pii: + """ + class Meta: + app_label = "bulk_email" + + course_id = CourseKeyField(max_length=255, db_index=True, unique=True) + + @classmethod + def instructor_email_disabled_for_course(cls, course_id): + """ + Returns whether or not email is disabled for the given course id. + """ + try: + return cls.objects.filter(course_id=course_id).exists() + except cls.DoesNotExist: + return False + + class BulkEmailFlag(ConfigurationModel): """ Enables site-wide configuration for the bulk_email feature. diff --git a/lms/djangoapps/bulk_email/models_api.py b/lms/djangoapps/bulk_email/models_api.py index 2e3799a50b..eef00ae880 100644 --- a/lms/djangoapps/bulk_email/models_api.py +++ b/lms/djangoapps/bulk_email/models_api.py @@ -3,7 +3,7 @@ Provides Python APIs exposed from Bulk Email models. """ -from lms.djangoapps.bulk_email.models import BulkEmailFlag, CourseAuthorization, Optout +from lms.djangoapps.bulk_email.models import BulkEmailFlag, CourseAuthorization, DisabledCourse, Optout def is_user_opted_out_for_course(user, course_id): @@ -48,3 +48,15 @@ def is_bulk_email_enabled_for_course(course_id): associated with the course_id; False otherwise """ return CourseAuthorization.instructor_email_enabled(course_id) + + +def is_bulk_email_disabled_for_course(course_id): + """ + Arguments: + course_id: the course id of the course + + Returns: + bool: True if the Bulk Email feature is disabled for the course + associated with the course_id; False otherwise + """ + return DisabledCourse.instructor_email_disabled_for_course(course_id) diff --git a/lms/djangoapps/bulk_email/tests/test_models.py b/lms/djangoapps/bulk_email/tests/test_models.py index 5699f00253..b7719618ca 100644 --- a/lms/djangoapps/bulk_email/tests/test_models.py +++ b/lms/djangoapps/bulk_email/tests/test_models.py @@ -25,8 +25,10 @@ from lms.djangoapps.bulk_email.models import ( CourseAuthorization, CourseEmail, CourseEmailTemplate, + DisabledCourse, Optout ) +from lms.djangoapps.bulk_email.models_api import is_bulk_email_disabled_for_course from lms.djangoapps.bulk_email.tests.factories import TargetFactory from openedx.core.djangoapps.course_groups.models import CourseCohort from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -314,6 +316,27 @@ class CourseAuthorizationTest(TestCase): assert is_bulk_email_feature_enabled(course_id) +class DisabledCourseTest(TestCase): + """ + Test DisabledCourse model and api + """ + def tearDown(self): + super().tearDown() + BulkEmailFlag.objects.all().delete() + + def test_is_email_disabled_for_course(self): + BulkEmailFlag.objects.create(enabled=True) + course_id = CourseKey.from_string('abc/123/doremi') + # Test that course is not disabled by default + assert not is_bulk_email_disabled_for_course(course_id) + + # Disable the course + disabled_course = DisabledCourse(course_id=course_id) + disabled_course.save() + # Course should be disabled + assert is_bulk_email_disabled_for_course(course_id) + + class TargetFilterTest(ModuleStoreTestCase): """ Tests for the optional filtering of recipients from the results of the `get_users` method of the Target model.