fix: Include refs to pre-RFC drafts as refs to the RFC (#6784)
* fix: clean up shadowed name in document_referenced_by.html * fix: include refs to rfc's came_from_draft() * fix: include refs to draft's became_rfc() * fix: Count indirect refs by RFCs * refactor: break indirect ref_by counting to its own fn * fix: only count refs to pre-rfc draft, not post-draft rfc (and rename a method) * test: test referenced_by_rfcs methods The test_referenced_by_rfcs_as_rfc_or_draft() test fails because there's a bug! * test: actually, do double-count refs to rfc/draft Let's do include refs to an rfc and its precursor draft as separate refs. This almost surely indicates a data error because it would mean an rfc referenced both an rfc and the draft that it came from. That should never be allowed, so at least let some light fall on it if it happens. * chore: Add docstring to document_referenced_by view
This commit is contained in:
parent
f5bd078351
commit
149f82f578
|
@ -651,8 +651,8 @@ class DocumentInfo(models.Model):
|
|||
| 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 @@ class DocumentInfo(models.Model):
|
|||
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
|
||||
|
||||
|
|
|
@ -2951,4 +2951,51 @@ class DocInfoMethodsTests(TestCase):
|
|||
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"),
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -38,10 +38,10 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{% for ref in refs %}
|
||||
{% with ref.source.name as name %}
|
||||
{% with ref.source.name as src_name %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'ietf.doc.views_doc.document_main' name=name %}">{{ name|prettystdname }}</a>
|
||||
<a href="{% url 'ietf.doc.views_doc.document_main' name=src_name %}">{{ src_name|prettystdname }}</a>
|
||||
{% if ref.target.name != name %}
|
||||
<br>
|
||||
<span class="badge rounded-pill text-bg-info">As {{ ref.target.name }}</span>
|
||||
|
@ -51,13 +51,13 @@
|
|||
<b>{{ ref.source.title }}</b>
|
||||
<br>
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_doc.document_references' name %}"
|
||||
href="{% url 'ietf.doc.views_doc.document_references' src_name %}"
|
||||
rel="nofollow">
|
||||
<i class="bi bi-arrow-left"></i>
|
||||
References
|
||||
</a>
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_doc.document_referenced_by' name %}"
|
||||
href="{% url 'ietf.doc.views_doc.document_referenced_by' src_name %}"
|
||||
rel="nofollow">
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
Referenced by
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
<td>{{ doc.pub_date|date:"b Y"|title }}</td>
|
||||
<td>{{ doc.title|urlize_ietf_docs }}</td>
|
||||
<td class="text-end">
|
||||
{% with doc.referenced_by_rfcs.count as refbycount %}
|
||||
{% with doc.referenced_by_rfcs_as_rfc_or_draft.count as refbycount %}
|
||||
{% if refbycount %}
|
||||
<a class="text-end"
|
||||
href="{% url 'ietf.doc.views_doc.document_referenced_by' doc.name %}"
|
||||
|
|
Loading…
Reference in a new issue