Repository: inducer/relate

Issue:
BUG: Event object creation not validated
1. `kind` can be any string, although it declared in  `help_text`  that `Should be lower_case_with_underscores, no spaces allowed.`.
2.  if `end_time` is not None, it must not be a value ahead of `time` (start_time).


Discussion:

Resolving patch:
diff --git a/course/constants.py b/course/constants.py
--- a/course/constants.py
+++ b/course/constants.py
@@ -36,6 +36,7 @@
 
 NAME_VALID_REGEX = r"^\w+$"
 COURSE_ID_REGEX = "(?P<course_identifier>[-a-zA-Z0-9]+)"
+EVENT_KIND_REGEX = "(?P<event_kind>[_a-z0-9]+)"
 FLOW_ID_REGEX = "(?P<flow_id>[-_a-zA-Z0-9]+)"
 GRADING_OPP_ID_REGEX = "(?P<grading_opp_id>[-_a-zA-Z0-9]+)"
 # FIXME : Support page hierarchy. Add '/' here, fix validation code.
diff --git a/course/models.py b/course/models.py
--- a/course/models.py
+++ b/course/models.py
@@ -52,7 +52,7 @@
         exam_ticket_states, EXAM_TICKET_STATE_CHOICES,
         participation_permission, PARTICIPATION_PERMISSION_CHOICES,
 
-        COURSE_ID_REGEX, GRADING_OPP_ID_REGEX, NAME_VALID_REGEX
+        COURSE_ID_REGEX, GRADING_OPP_ID_REGEX, NAME_VALID_REGEX, EVENT_KIND_REGEX
         )
 
 from course.page.base import AnswerFeedback
@@ -291,7 +291,14 @@ class Event(models.Model):
             # Translators: format of event kind in Event model
             help_text=_("Should be lower_case_with_underscores, no spaces "
             "allowed."),
-            verbose_name=_('Kind of event'))
+            verbose_name=_('Kind of event'),
+            validators=[
+                RegexValidator(
+                    "^" + EVENT_KIND_REGEX + "$",
+                    message=_("Should be lower_case_with_underscores, no spaces "
+                              "allowed.")),
+                ]
+            )
     ordinal = models.IntegerField(blank=True, null=True,
             # Translators: ordinal of event of the same kind
             verbose_name=_('Ordinal of event'))


Test patch:
diff --git a/tests/test_models.py b/tests/test_models.py
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -131,6 +131,33 @@ def test_unicode(self):
                                         ordinal=2)
         self.assertNotEqual(str(event3), str(event4))
 
+    def test_validate_kind_with_spaces(self):
+        with self.assertRaises(ValidationError) as cm:
+            factories.EventFactory(course=self.course, kind="my event")
+
+        expected_error_msg = (
+            "Should be lower_case_with_underscores, no spaces "
+            "allowed.")
+        self.assertIn(expected_error_msg, cm.exception.message_dict["kind"])
+
+    def test_validate_kind_with_upper_case(self):
+        with self.assertRaises(ValidationError) as cm:
+            factories.EventFactory(course=self.course, kind="myEvent")
+
+        expected_error_msg = (
+            "Should be lower_case_with_underscores, no spaces "
+            "allowed.")
+        self.assertIn(expected_error_msg, cm.exception.message_dict["kind"])
+
+    def test_validate_kind_with_hyphen(self):
+        with self.assertRaises(ValidationError) as cm:
+            factories.EventFactory(course=self.course, kind="my-event")
+
+        expected_error_msg = (
+            "Should be lower_case_with_underscores, no spaces "
+            "allowed.")
+        self.assertIn(expected_error_msg, cm.exception.message_dict["kind"])
+
     def test_clean_end_time(self):
         with self.assertRaises(ValidationError) as cm:
             factories.EventFactory(