Repository: carpentries/amy

Issue:
Require conditional confirmation that workshops <2 mos away may not be possible.
Issue #1683 resolved by PR #1691 added a box to the workshop request and inquiry forms noting that if the workshop was less than two months away, we  can not guarantee availability of Instructors.

This request is to build on that, to require and display it only if the workshop is less than two months away OR if the workshop date is unknown.


Discussion:
Putting this on hold as we re-consider how to handle workshops that are too close in the future.
Revisiting this - we do want to have  the checkbox that is currently always visible to be visible only conditionally, depending on the workshop date.  Not very high priority though.

Resolving patch:
diff --git a/amy/extrequests/forms.py b/amy/extrequests/forms.py
--- a/amy/extrequests/forms.py
+++ b/amy/extrequests/forms.py
@@ -262,7 +262,7 @@ class WorkshopRequestBaseForm(forms.ModelForm):
         label=WorkshopRequest._meta.get_field("host_responsibilities").verbose_name,
     )
     instructor_availability = forms.BooleanField(
-        required=True,
+        required=False,
         label=WorkshopRequest._meta.get_field("instructor_availability").verbose_name,
     )
 
@@ -286,6 +286,9 @@ class WorkshopRequestBaseForm(forms.ModelForm):
 
     helper = BootstrapHelper(add_cancel_button=False)
 
+    class Media:
+        js = ("instructor_availability_checkbox.js",)
+
     class Meta:
         model = WorkshopRequest
         fields = (
@@ -548,6 +551,20 @@ def clean(self):
                 'If you entered data in "Other" field, please select that ' "option."
             )
 
+        # 7: if workshop is less than 2mo away, or if the dates are unknown, require the
+        # confirmation in `instructor_availability`:
+        instructor_availability: bool = self.cleaned_data.get("instructor_availability")
+        two_months_away = datetime.date.today() + datetime.timedelta(days=60)
+        if (
+            preferred_dates and preferred_dates <= two_months_away
+        ) or not preferred_dates:
+            if not instructor_availability:
+                errors["instructor_availability"] = ValidationError(
+                    "Please confirm instructor availability, since the workshop is "
+                    'planned for less than 2 months away or "Other" arrangements '
+                    "were selected."
+                )
+
         # raise errors if any present
         if errors:
             raise ValidationError(errors)
@@ -628,7 +645,7 @@ class WorkshopInquiryRequestBaseForm(forms.ModelForm):
         ).verbose_name,
     )
     instructor_availability = forms.BooleanField(
-        required=True,
+        required=False,
         label=WorkshopInquiryRequest._meta.get_field(
             "instructor_availability"
         ).verbose_name,
@@ -671,6 +688,9 @@ class WorkshopInquiryRequestBaseForm(forms.ModelForm):
 
     helper = BootstrapHelper(add_cancel_button=False)
 
+    class Media:
+        js = ("instructor_availability_checkbox.js",)
+
     class Meta:
         model = WorkshopInquiryRequest
         fields = (
@@ -1013,6 +1033,19 @@ def clean(self):
                 'If you entered data in "Other" field, please select that ' "option."
             )
 
+        # 7: if workshop is less than 2mo away, or if the dates are unknown, require the
+        # confirmation in `instructor_availability`:
+        instructor_availability: bool = self.cleaned_data.get("instructor_availability")
+        two_months_away = datetime.date.today() + datetime.timedelta(days=60)
+        if (
+            not preferred_dates or preferred_dates <= two_months_away
+        ) and not instructor_availability:
+            errors["instructor_availability"] = ValidationError(
+                "Please confirm instructor availability, since the workshop is "
+                'planned for less than 2 months away or "Other" arrangements '
+                "were selected."
+            )
+
         # raise errors if any present
         if errors:
             raise ValidationError(errors)


Test patch:
diff --git a/amy/extrequests/tests/test_workshop_inquiries.py b/amy/extrequests/tests/test_workshop_inquiries.py
--- a/amy/extrequests/tests/test_workshop_inquiries.py
+++ b/amy/extrequests/tests/test_workshop_inquiries.py
@@ -347,6 +347,57 @@ def test_public_event(self):
             blank=True,
         )
 
+    def test_instructor_availability_required(self):
+        """Test requiredness of `instructor_availability` depending on selected
+        preferred dates."""
+        # Arrange
+        data1 = {
+            "preferred_dates": date.today() + timedelta(days=30),
+            "other_preferred_dates": "",
+            "instructor_availability": "",
+        }
+        data2 = {
+            "preferred_dates": "",
+            "other_preferred_dates": "sometime in future",
+            "instructor_availability": "",
+        }
+        # Act
+        form1 = WorkshopInquiryRequestBaseForm(data1)
+        form2 = WorkshopInquiryRequestBaseForm(data2)
+        # Assert
+        for form in (form1, form2):
+            self.assertNotIn("preferred_dates", form.errors)
+            self.assertNotIn("other_preferred_dates", form.errors)
+            self.assertIn("instructor_availability", form.errors)
+
+    def test_instructor_availability_not_required(self):
+        """Test `instructor_availability` not required in some circumstances."""
+        # Arrange
+        data1 = {
+            "preferred_dates": date.today() + timedelta(days=30),
+            "other_preferred_dates": "",
+            "instructor_availability": "1",
+        }
+        data2 = {
+            "preferred_dates": "",
+            "other_preferred_dates": "sometime in future",
+            "instructor_availability": "1",
+        }
+        data3 = {
+            "preferred_dates": date.today() + timedelta(days=61),
+            "other_preferred_dates": "",
+            "instructor_availability": "",
+        }
+        # Act
+        form1 = WorkshopInquiryRequestBaseForm(data1)
+        form2 = WorkshopInquiryRequestBaseForm(data2)
+        form3 = WorkshopInquiryRequestBaseForm(data3)
+        # Assert
+        for form in (form1, form2, form3):
+            self.assertNotIn("preferred_dates", form.errors)
+            self.assertNotIn("other_preferred_dates", form.errors)
+            self.assertNotIn("instructor_availability", form.errors)
+
 
 class TestWorkshopInquiryViews(TestBase):
     def setUp(self):
diff --git a/amy/extrequests/tests/test_workshop_requests.py b/amy/extrequests/tests/test_workshop_requests.py
--- a/amy/extrequests/tests/test_workshop_requests.py
+++ b/amy/extrequests/tests/test_workshop_requests.py
@@ -293,6 +293,57 @@ def test_public_event(self):
             first_when_other="other",
         )
 
+    def test_instructor_availability_required(self):
+        """Test requiredness of `instructor_availability` depending on selected
+        preferred dates."""
+        # Arrange
+        data1 = {
+            "preferred_dates": date.today() + timedelta(days=30),
+            "other_preferred_dates": "",
+            "instructor_availability": "",
+        }
+        data2 = {
+            "preferred_dates": "",
+            "other_preferred_dates": "sometime in future",
+            "instructor_availability": "",
+        }
+        # Act
+        form1 = WorkshopRequestBaseForm(data1)
+        form2 = WorkshopRequestBaseForm(data2)
+        # Assert
+        for form in (form1, form2):
+            self.assertNotIn("preferred_dates", form.errors)
+            self.assertNotIn("other_preferred_dates", form.errors)
+            self.assertIn("instructor_availability", form.errors)
+
+    def test_instructor_availability_not_required(self):
+        """Test `instructor_availability` not required in some circumstances."""
+        # Arrange
+        data1 = {
+            "preferred_dates": date.today() + timedelta(days=30),
+            "other_preferred_dates": "",
+            "instructor_availability": "1",
+        }
+        data2 = {
+            "preferred_dates": "",
+            "other_preferred_dates": "sometime in future",
+            "instructor_availability": "1",
+        }
+        data3 = {
+            "preferred_dates": date.today() + timedelta(days=61),
+            "other_preferred_dates": "",
+            "instructor_availability": "",
+        }
+        # Act
+        form1 = WorkshopRequestBaseForm(data1)
+        form2 = WorkshopRequestBaseForm(data2)
+        form3 = WorkshopRequestBaseForm(data3)
+        # Assert
+        for form in (form1, form2, form3):
+            self.assertNotIn("preferred_dates", form.errors)
+            self.assertNotIn("other_preferred_dates", form.errors)
+            self.assertNotIn("instructor_availability", form.errors)
+
 
 class TestWorkshopRequestViews(TestBase):
     def setUp(self):