Repository: ietf-tools/datatracker

Issue:
Draft submission with empty strings in date element fails with generic "Meta-Data errors found!" message
### Describe the issue

I tried submitting an xml draft, hard fail due to "Meta-Data error found".   Very odd since it passes the submission checks.

There is a closed issue that sounds similar, but apparently not fixed.

I can send the xml, but this doesn't allow that file type.

<img width="1009" alt="Image" src="https://github.com/ietf-tools/datatracker/assets/6423658/fb3e7616-ea04-46e8-a6d2-0d359888f7b7">



### Code of Conduct

- [X] I agree to follow the [IETF's Code of Conduct](https://github.com/ietf-tools/.github/blob/main/CODE_OF_CONDUCT.md)


Discussion:
This is similar in presentation to the recently closed issue but is a new bug. It appears to be related to your draft's contents - I see the failures in the logs and other drafts have been successfully uploaded in between attempts.

The back end is failing with the following traceback
```
Traceback (most recent call last):
  File "/workspace/ietf/submit/utils.py", line 1265, in process_and_validate_submission
    xml_metadata = process_submission_xml(submission.name, submission.rev)
  File "/workspace/ietf/submit/utils.py", line 1166, in process_submission_xml
    "document_date": xml_draft.get_creation_date(),
  File "/workspace/ietf/utils/xmldraft.py", line 154, in get_creation_date
    return datetime.date(year, month, day)
TypeError: an integer is required (got type str)
```

The parser is having a problem with the date element in your draft's front section. Can you post that (or zip the entire xml and attach, I believe github will allow you to attach it as a zip)?

Thank you for the report.
[draft-ietf-6man-hbh-processing-09.xml.zip](https://github.com/ietf-tools/datatracker/files/11951620/draft-ietf-6man-hbh-processing-09.xml.zip)

The date element in the draft hasn't changed for a long time.   The draft is -09.
Thanks- the problem is triggered because your `<date>` element has empty fields. If you fill in those values or remove the element entirely, I expect it will be accepted. You can probably also just use an empty `<date/>` element without the `year`, `month`, and `day`.

I believe the date field is invalid as it is. It's likely the parser looked the other way in the past and treated is as if it were absent.

We should coordinate with xml2rfc on how we handle this. Obviously we need to give better feedback here if we're not going to accept this format.
Also, the impression that submission checks passed is false, caused by #5696. (In truth, they were not run at all because the submission was rejected before getting to that point.)
Just checked and xml2rfc accepts this, treating it as though the year/month/day were not present, so datatracker should do the same.
Thanks, removing the date field fixed the problem.

Resolving patch:
diff --git a/ietf/utils/xmldraft.py b/ietf/utils/xmldraft.py
--- a/ietf/utils/xmldraft.py
+++ b/ietf/utils/xmldraft.py
@@ -136,24 +136,27 @@ def _parse_docname(self):
     def get_title(self):
         return self.xmlroot.findtext('front/title').strip()
 
+    @staticmethod
+    def parse_creation_date(date_elt):
+        if date_elt is None:
+            return None
+        today = date_today()
+        # ths mimics handling of date elements in the xml2rfc text/html writers
+        year, month, day = extract_date(date_elt, today)
+        year, month, day = augment_date(year, month, day, today)
+        if not day:
+            # Must choose a day for a datetime.date. Per RFC 7991 sect 2.17, we use
+            # today's date if it is consistent with the rest of the date. Otherwise,
+            # arbitrariy (and consistent with the text parser) assume the 15th.
+            if year == today.year and month == today.month:
+                day = today.day
+            else:
+                day = 15
+        return datetime.date(year, month, day)
+
     def get_creation_date(self):
-        date_elt = self.xmlroot.find("front/date")
-        if date_elt is not None:
-            # ths mimics handling of date elements in the xml2rfc text/html writers
-            today = date_today()
-            year, month, day = extract_date(date_elt, today)
-            year, month, day = augment_date(year, month, day, today)
-            if day is None:
-                # Must choose a day for a datetime.date. Per RFC 7991 sect 2.17, we use
-                # today's date if it is consistent with the rest of the date. Otherwise,
-                # arbitrariy (and consistent with the text parser) assume the 15th.
-                if year == today.year and month == today.month:
-                    day = today.day
-                else:
-                    day = 15
-            return datetime.date(year, month, day)
-        return None
-    
+        return self.parse_creation_date(self.xmlroot.find("front/date"))
+
     # todo fix the implementation of XMLDraft.get_abstract()
     #
     # This code was pulled from ietf.submit.forms where it existed for some time.


Test patch:
diff --git a/ietf/utils/tests.py b/ietf/utils/tests.py
--- a/ietf/utils/tests.py
+++ b/ietf/utils/tests.py
@@ -400,6 +400,56 @@ def test_get_refs_v2(self):
             }
         )
 
+    def test_parse_creation_date(self):
+        # override date_today to avoid skew when test runs around midnight
+        today = datetime.date.today()
+        with patch("ietf.utils.xmldraft.date_today", return_value=today):
+            # Note: using a dict as a stand-in for XML elements, which rely on the get() method
+            self.assertEqual(
+                XMLDraft.parse_creation_date({"year": "2022", "month": "11", "day": "24"}),
+                datetime.date(2022, 11, 24),
+                "Fully specified date should be parsed",
+            )
+            self.assertEqual(
+                XMLDraft.parse_creation_date(None), None, "return None if input is None"
+            )
+            # Cases where the date is empty - missing fields or fields filled in with blank strings.
+            self.assertEqual(XMLDraft.parse_creation_date({}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({"day": ""}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({"year": ""}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({"month": ""}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({"day": ""}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({"year": "", "month": ""}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({"year": "", "day": ""}), today)
+            self.assertEqual(XMLDraft.parse_creation_date({"month": "", "day": ""}), today)
+            self.assertEqual(
+                XMLDraft.parse_creation_date({"year": "", "month": "", "day": ""}), today
+            )
+            self.assertEqual(
+                XMLDraft.parse_creation_date(
+                    {"year": str(today.year), "month": str(today.month), "day": ""}
+                ),
+                today,
+            )
+            # When year/month do not match, day should be 15th of the month
+            self.assertEqual(
+                XMLDraft.parse_creation_date(
+                    {"year": str(today.year - 1), "month": str(today.month), "day": ""}
+                ),
+                datetime.date(today.year - 1, today.month, 15),
+            )
+            self.assertEqual(
+                XMLDraft.parse_creation_date(
+                    {
+                        "year": str(today.year),
+                        "month": "1" if today.month != 1 else "2",
+                        "day": "",
+                    }
+                ),
+                datetime.date(today.year, 1 if today.month != 1 else 2, 15),
+            )
+
 
 class NameTests(TestCase):