Repository: ietf-tools/datatracker

Issue:
Disclaimer banner for unadopted I-Ds
### Description

(The design and text of this enhancement has the consensus of the IESG, and concurrence of the IETF, IAB, IRTF and ISE stream managers)

Create a banner in the datatracker with the following text when the draft is active and the "RFC Stream" field = "None":

==[ banner text ]==
Currently, this document is an Internet-Draft (I-D) not an RFC. Anyone may submit an I-D, no prior permission or membership is required. This individual I-D is not endorsed by the IETF and has no formal standing in the [IETF standards process](RFC2026).
==[ banner text ]==

Notionally the display of the banner is sketched at https://docs.google.com/presentation/d/1bg9V2GFbHbWQ1LrJ3w6EuAxiKjgm6pmRuUfCTwftDWM/edit#slide=id.g23f74cb6a64_0_22.


### 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:
The logic on when to show this banner is more complicated than stream==None or not.

The IETF stream, in particular, has several "pre adoption" stream states, and a document in those states is in the stream.

See https://datatracker.ietf.org/help/state/draft-stream-ietf

For what states does this label get applied or not? I suspect the label should still show for "Candidate for adoption" and "Call for adoption issued".  Should it show for "Adopted for information only"? Should it show for "Adopted by a WG" state that's different from "WG Document"?

cc: @larseggert 



Resolving patch:
diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py
--- a/ietf/doc/templatetags/ietf_filters.py
+++ b/ietf/doc/templatetags/ietf_filters.py
@@ -877,3 +877,28 @@ def badgeify(blob):
             )
 
     return text
+
+
+@register.filter
+def is_in_stream(doc):
+    """
+    Check if the doc is in one of the states in it stream that
+    indicate that is actually adopted, i.e., part of the stream.
+    (There are various "candidate" states that necessitate this
+    filter.)
+    """
+    if not doc.stream:
+        return False
+    stream = doc.stream.slug
+    state = doc.get_state_slug(f"draft-stream-{doc.stream.slug}")
+    if not state:
+        return True
+    if stream == "ietf":
+        return state not in ["wg-cand", "c-adopt"]
+    elif stream == "irtf":
+        return state != "candidat"
+    elif stream == "iab":
+        return state not in ["candidat", "diff-org"]
+    elif stream == "editorial":
+        return True
+    return False


Test patch:
diff --git a/ietf/doc/templatetags/tests_ietf_filters.py b/ietf/doc/templatetags/tests_ietf_filters.py
--- a/ietf/doc/templatetags/tests_ietf_filters.py
+++ b/ietf/doc/templatetags/tests_ietf_filters.py
@@ -7,9 +7,20 @@
     IndividualDraftFactory,
     CharterFactory,
     NewRevisionDocEventFactory,
+    StatusChangeFactory,
+    RgDraftFactory,
+    EditorialDraftFactory,
+    WgDraftFactory,
+    ConflictReviewFactory,
+    BofreqFactory,
+    StatementFactory,
 )
 from ietf.doc.models import DocEvent
-from ietf.doc.templatetags.ietf_filters import urlize_ietf_docs, is_valid_url
+from ietf.doc.templatetags.ietf_filters import (
+    urlize_ietf_docs,
+    is_valid_url,
+    is_in_stream,
+)
 from ietf.person.models import Person
 from ietf.utils.test_utils import TestCase
 
@@ -19,13 +30,28 @@
 
 
 class IetfFiltersTests(TestCase):
+    def test_is_in_stream(self):
+        for draft in [
+            IndividualDraftFactory(),
+            CharterFactory(),
+            StatusChangeFactory(),
+            ConflictReviewFactory(),
+            StatementFactory(),
+            BofreqFactory(),
+        ]:
+            self.assertFalse(is_in_stream(draft))
+        for draft in [RgDraftFactory(), WgDraftFactory(), EditorialDraftFactory()]:
+            self.assertTrue(is_in_stream(draft))
+        for stream in ["iab", "ietf", "irtf", "ise", "editorial"]:
+            self.assertTrue(is_in_stream(IndividualDraftFactory(stream_id=stream)))
+
     def test_is_valid_url(self):
         cases = [(settings.IDTRACKER_BASE_URL, True), ("not valid", False)]
         for url, result in cases:
             self.assertEqual(is_valid_url(url), result)
 
     def test_urlize_ietf_docs(self):
-        rfc = WgRfcFactory(rfc_number=123456,std_level_id="bcp")
+        rfc = WgRfcFactory(rfc_number=123456, std_level_id="bcp")
         rfc.save_with_history(
             [
                 DocEvent.objects.create(
@@ -57,7 +83,6 @@ def test_urlize_ietf_docs(self):
 
         cases = [
             ("no change", "no change"),
-
             # TODO: rework subseries when we add them
             # ("bCp123456", '<a href="/doc/bcp123456/">bCp123456</a>'),
             # ("Std 00123456", '<a href="/doc/std123456/">Std 00123456</a>'),