diff --git a/ietf/doc/models.py b/ietf/doc/models.py index fdda23ecd14..9275b541015 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -651,8 +651,8 @@ def referenced_by(self): | models.Q(source__type__slug="rfc") ) - def referenced_by_rfcs(self): + """Get refs to this doc from RFCs""" return self.relations_that(("refnorm", "refinfo", "refunk", "refold")).filter( source__type__slug="rfc" ) @@ -675,6 +675,13 @@ def contains(self): def part_of(self): return self.related_that("contains") + def referenced_by_rfcs_as_rfc_or_draft(self): + """Get refs to this doc, or a draft/rfc it came from, from an RFC""" + refs_to = self.referenced_by_rfcs() + if self.type_id == "rfc" and self.came_from_draft(): + refs_to |= self.came_from_draft().referenced_by_rfcs() + return refs_to + class Meta: abstract = True diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index f14b5b1af0f..8ae588ad1dc 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -2951,4 +2951,51 @@ def test_revisions(self): self.assertEqual(draft.revisions_by_dochistory(),[f"{i:02d}" for i in range(8,10)]) self.assertEqual(draft.revisions_by_newrevisionevent(),[f"{i:02d}" for i in [*range(0,5), *range(6,10)]]) + def test_referenced_by_rfcs(self): + # n.b., no significance to the ref* values in this test + referring_draft = WgDraftFactory() + (rfc, referring_rfc) = WgRfcFactory.create_batch(2) + rfc.targets_related.create(relationship_id="refnorm", source=referring_draft) + rfc.targets_related.create(relationship_id="refnorm", source=referring_rfc) + self.assertCountEqual( + rfc.referenced_by_rfcs(), + rfc.targets_related.filter(source=referring_rfc), + ) + def test_referenced_by_rfcs_as_rfc_or_draft(self): + # n.b., no significance to the ref* values in this test + draft = WgDraftFactory() + rfc = WgRfcFactory() + draft.relateddocument_set.create(relationship_id="became_rfc", target=rfc) + + # Draft referring to the rfc and the draft - should not be reported at all + draft_referring_to_both = WgDraftFactory() + draft_referring_to_both.relateddocument_set.create(relationship_id="refnorm", target=draft) + draft_referring_to_both.relateddocument_set.create(relationship_id="refnorm", target=rfc) + + # RFC referring only to the draft - should be reported for either the draft or the rfc + rfc_referring_to_draft = WgRfcFactory() + rfc_referring_to_draft.relateddocument_set.create(relationship_id="refinfo", target=draft) + + # RFC referring only to the rfc - should be reported only for the rfc + rfc_referring_to_rfc = WgRfcFactory() + rfc_referring_to_rfc.relateddocument_set.create(relationship_id="refinfo", target=rfc) + + # RFC referring only to the rfc - should be reported only for the rfc + rfc_referring_to_rfc = WgRfcFactory() + rfc_referring_to_rfc.relateddocument_set.create(relationship_id="refinfo", target=rfc) + + # RFC referring to the rfc and the draft - should be reported for both + rfc_referring_to_both = WgRfcFactory() + rfc_referring_to_both.relateddocument_set.create(relationship_id="refnorm", target=draft) + rfc_referring_to_both.relateddocument_set.create(relationship_id="refnorm", target=rfc) + + self.assertCountEqual( + draft.referenced_by_rfcs_as_rfc_or_draft(), + draft.targets_related.filter(source__type="rfc"), + ) + + self.assertCountEqual( + rfc.referenced_by_rfcs_as_rfc_or_draft(), + draft.targets_related.filter(source__type="rfc") | rfc.targets_related.filter(source__type="rfc"), + ) diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index 8408f5a0cd5..665393c24e8 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -1437,8 +1437,26 @@ def document_references(request, name): return render(request, "doc/document_references.html",dict(doc=doc,refs=sorted(refs,key=lambda x:x.target.name),)) def document_referenced_by(request, name): + """View documents that reference the named document + + The view lists both direct references to a the named document, plus references to + related other documents. For a draft that became an RFC, this will include references + to the RFC. For an RFC, this will include references to the draft it came from, if any. + For a subseries document, this will include references to any of the RFC documents it + contains. + + In the rendered output, a badge is applied to indicate the name of the document the + reference actually targeted. E.g., on the display for a draft that became RFC NNN, + references included because they point to that RFC would be shown with a tag "As RFC NNN". + The intention is to make the "Referenced By" page useful for finding related work while + accurately reflecting the actual reference relationships. + """ doc = get_object_or_404(Document,name=name) refs = doc.referenced_by() + if doc.came_from_draft(): + refs |= doc.came_from_draft().referenced_by() + if doc.became_rfc(): + refs |= doc.became_rfc().referenced_by() if doc.type_id in ["bcp","std","fyi"]: for rfc in doc.contains(): refs |= rfc.referenced_by() diff --git a/ietf/templates/doc/document_referenced_by.html b/ietf/templates/doc/document_referenced_by.html index 2c1729f99c4..e1137768b71 100644 --- a/ietf/templates/doc/document_referenced_by.html +++ b/ietf/templates/doc/document_referenced_by.html @@ -38,10 +38,10 @@