From 831a8bcc3682c78deb0eae06c8247e1959681077 Mon Sep 17 00:00:00 2001 From: Collin Preston Date: Tue, 21 Mar 2023 10:46:52 -0400 Subject: [PATCH] feat: add course mode expiration explicit to admin (#31289) * feat: add course mode expiration explicit to admin Adds a checkbox for defining the expiration_datetime_is_explicit to the course_mode Django admin screen. * fix: Change labels to use "lock" * fix: increment migration name number * fix: delete migration delete the migration and recreate in the next commit * fix: add back migration Add back the migration to hopefully fix strange failing test. * fix: fix failing test --- common/djangoapps/course_modes/admin.py | 7 ++++++ ...0015_expiration_datetime_explicit_admin.py | 23 +++++++++++++++++++ common/djangoapps/course_modes/models.py | 9 +++++++- .../course_modes/tests/test_admin.py | 11 ++++++++- 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 common/djangoapps/course_modes/migrations/0015_expiration_datetime_explicit_admin.py diff --git a/common/djangoapps/course_modes/admin.py b/common/djangoapps/course_modes/admin.py index 4563234566..c874a78925 100644 --- a/common/djangoapps/course_modes/admin.py +++ b/common/djangoapps/course_modes/admin.py @@ -125,6 +125,12 @@ class CourseModeForm(forms.ModelForm): mode_slug = cleaned_data.get("mode_slug") upgrade_deadline = cleaned_data.get("_expiration_datetime") verification_deadline = cleaned_data.get("verification_deadline") + expiration_datetime_is_explicit = cleaned_data.get("expiration_datetime_is_explicit") + + if expiration_datetime_is_explicit and upgrade_deadline is None: + raise forms.ValidationError( + "An upgrade deadline must be specified when setting Lock upgrade deadline date to True." + ) # Allow upgrade deadlines ONLY for the "verified" mode # This avoids a nasty error condition in which the upgrade deadline is set @@ -189,6 +195,7 @@ class CourseModeAdmin(admin.ModelAdmin): 'min_price', 'currency', '_expiration_datetime', + 'expiration_datetime_is_explicit', 'verification_deadline', 'sku', 'android_sku', diff --git a/common/djangoapps/course_modes/migrations/0015_expiration_datetime_explicit_admin.py b/common/djangoapps/course_modes/migrations/0015_expiration_datetime_explicit_admin.py new file mode 100644 index 0000000000..bcb516bfd7 --- /dev/null +++ b/common/djangoapps/course_modes/migrations/0015_expiration_datetime_explicit_admin.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.18 on 2023-03-06 20:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('course_modes', '0014_auto_20230207_1212'), + ] + + operations = [ + migrations.AlterField( + model_name='coursemode', + name='expiration_datetime_is_explicit', + field=models.BooleanField(default=False, help_text='OPTIONAL: Set to True to lock in the explicitly defined upgrade deadline date. Set to False if there is no upgrade deadline or to use the default upgrade deadline.', verbose_name='Lock upgrade deadline date'), + ), + migrations.AlterField( + model_name='historicalcoursemode', + name='expiration_datetime_is_explicit', + field=models.BooleanField(default=False, help_text='OPTIONAL: Set to True to lock in the explicitly defined upgrade deadline date. Set to False if there is no upgrade deadline or to use the default upgrade deadline.', verbose_name='Lock upgrade deadline date'), + ), + ] diff --git a/common/djangoapps/course_modes/models.py b/common/djangoapps/course_modes/models.py index 2d92a99d2c..2e711a1081 100644 --- a/common/djangoapps/course_modes/models.py +++ b/common/djangoapps/course_modes/models.py @@ -89,7 +89,14 @@ class CourseMode(models.Model): # The system prefers to set this automatically based on default settings. But # if the field is set manually we want a way to indicate that so we don't # overwrite the manual setting of the field. - expiration_datetime_is_explicit = models.BooleanField(default=False) + expiration_datetime_is_explicit = models.BooleanField( + default=False, + verbose_name=_("Lock upgrade deadline date"), + help_text=_( + "OPTIONAL: Set to True to lock in the explicitly defined upgrade deadline date. " + "Set to False if there is no upgrade deadline or to use the default upgrade deadline." + ) + ) # DEPRECATED: the `expiration_date` field has been replaced by `expiration_datetime` expiration_date = models.DateField(default=None, null=True, blank=True) diff --git a/common/djangoapps/course_modes/tests/test_admin.py b/common/djangoapps/course_modes/tests/test_admin.py index 81cd837089..52640dc52f 100644 --- a/common/djangoapps/course_modes/tests/test_admin.py +++ b/common/djangoapps/course_modes/tests/test_admin.py @@ -163,6 +163,14 @@ class AdminCourseModeFormTest(ModuleStoreTestCase): 'For other modes, please set the enrollment end date in Studio.' )) + def test_validate_expiration_datetime_is_explicit_only_with_upgrade_deadline(self): + # Only allow the expiration_datetime_is_explicit to be True if the upgrade_deadline is + # defined with a date, otherwise cause a validation error. + form = self._admin_form("verified", expiration_datetime_is_explicit=True) + self._assert_form_has_error(form, ( + "An upgrade deadline must be specified when setting Lock upgrade deadline date to True." + )) + @ddt.data("honor", "no-id-professional", "credit") def test_validate_verification_deadline_only_for_verified(self, course_mode): # Only the verified mode should have a verification deadline set. @@ -192,7 +200,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase): return CourseModeForm(instance=course_mode) - def _admin_form(self, mode, upgrade_deadline=None): + def _admin_form(self, mode, upgrade_deadline=None, expiration_datetime_is_explicit=False): """Load the course mode admin form. """ course_mode = CourseModeFactory.create( course_id=self.course.id, @@ -203,6 +211,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase): "mode_slug": mode, "mode_display_name": mode, "_expiration_datetime": upgrade_deadline, + "expiration_datetime_is_explicit": expiration_datetime_is_explicit, "currency": "usd", "min_price": 10, }, instance=course_mode)