Adds pages to show what a given document refers to and what refers to it.
Fixes bug #1194 commit ready for merge - Legacy-Id: 6701
This commit is contained in:
parent
a677a70df3
commit
d19967ac93
|
@ -167,6 +167,34 @@ class RelatedDocument(models.Model):
|
|||
def __unicode__(self):
|
||||
return u"%s %s %s" % (self.source.name, self.relationship.name.lower(), self.target.name)
|
||||
|
||||
def is_downref(self):
|
||||
|
||||
if self.source.type.slug!='draft' or self.relationship.slug not in ['refnorm','refold','refunk']:
|
||||
return None
|
||||
|
||||
if self.source.get_state().slug == 'rfc':
|
||||
source_lvl = self.source.std_level.slug
|
||||
else:
|
||||
source_lvl = self.source.intended_std_level.slug
|
||||
|
||||
if source_lvl not in ['bcp','ps','ds','std']:
|
||||
return None
|
||||
|
||||
if self.target.document.get_state().slug == 'rfc':
|
||||
target_lvl = self.target.document.std_level.slug
|
||||
else:
|
||||
target_lvl = self.target.document.intended_std_level.slug
|
||||
|
||||
rank = { 'ps':1, 'ds':2, 'std':3, 'bcp':3 }
|
||||
|
||||
if ( target_lvl not in rank ) or ( rank[target_lvl] < rank[source_lvl] ):
|
||||
if self.relationship.slug == 'refnorm' and target_lvl!='unkn':
|
||||
return "Downref"
|
||||
else:
|
||||
return "Possible Downref"
|
||||
|
||||
return None
|
||||
|
||||
class DocumentAuthor(models.Model):
|
||||
document = models.ForeignKey('Document')
|
||||
author = models.ForeignKey(Email, help_text="Email address used by author for submission")
|
||||
|
|
|
@ -295,3 +295,21 @@ class TemplateTagTest(unittest.TestCase):
|
|||
from ietf.doc.templatetags import ietf_filters
|
||||
failures, tests = doctest.testmod(ietf_filters)
|
||||
self.assertEqual(failures, 0)
|
||||
|
||||
class ReferencesTest(TestCase):
|
||||
perma_fixtures = ['names']
|
||||
|
||||
def test_references(self):
|
||||
make_test_data()
|
||||
doc1 = Document.objects.get(name='draft-ietf-mars-test')
|
||||
doc2 = DocAlias.objects.get(name='draft-imaginary-independent-submission')
|
||||
RelatedDocument.objects.get_or_create(source=doc1,target=doc2,relationship=DocRelationshipName.objects.get(slug='refnorm'))
|
||||
url = urlreverse('doc_references', kwargs=dict(name=doc1.name))
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertTrue(doc2.name in r.content)
|
||||
url = urlreverse('doc_referenced_by', kwargs=dict(name=doc2.name))
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertTrue(doc1.name in r.content)
|
||||
|
||||
|
|
|
@ -60,6 +60,8 @@ urlpatterns += patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/history/$', views_doc.document_history, name="doc_history"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/writeup/$', views_doc.document_writeup, name="doc_writeup"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/shepherdwriteup/$', views_doc.document_shepherd_writeup, name="doc_shepherd_writeup"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/references/$', views_doc.document_references, name="doc_references"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/referencedby/$', views_doc.document_referenced_by, name="doc_referenced_by"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/position/$', views_ballot.edit_position),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/emailposition/$', views_ballot.send_ballot_comment, name='doc_send_ballot_comment'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
|
@ -97,6 +99,8 @@ urlpatterns += patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/makelastcall/$', views_ballot.make_last_call, name='doc_make_last_call'),
|
||||
|
||||
url(r'^help/state/(?P<type>[\w-]+)/$', 'ietf.doc.views_help.state_help', name="state_help"),
|
||||
url(r'^help/relationships/$', 'ietf.doc.views_help.relationship_help', name="relationship_help"),
|
||||
url(r'^help/relationships/(?P<subset>\w+)/$', 'ietf.doc.views_help.relationship_help', name="relationship_subset_help"),
|
||||
|
||||
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.wgcharter.urls')),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
|
||||
|
|
|
@ -609,6 +609,29 @@ def document_shepherd_writeup(request, name):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def document_references(request, name):
|
||||
doc = get_object_or_404(Document,docalias__name=name)
|
||||
refs = doc.relations_that_doc(['refnorm','refinfo','refunk','refold'])
|
||||
return render_to_response("doc/document_references.html",dict(doc=doc,refs=sorted(refs,key=lambda x:x.target.name),),context_instance=RequestContext(request))
|
||||
|
||||
def document_referenced_by(request, name):
|
||||
doc = get_object_or_404(Document,docalias__name=name)
|
||||
refs = doc.relations_that(['refnorm','refinfo','refunk','refold']).filter(source__states__type__slug='draft',source__states__slug__in=['rfc','active'])
|
||||
full = ( request.GET.get('full') != None )
|
||||
numdocs = refs.count()
|
||||
if not full and numdocs>250:
|
||||
refs=refs[:250]
|
||||
else:
|
||||
numdocs=None
|
||||
refs=sorted(refs,key=lambda x:(['refnorm','refinfo','refunk','refold'].index(x.relationship.slug),x.source.canonical_name()))
|
||||
return render_to_response("doc/document_referenced_by.html",
|
||||
dict(alias_name=name,
|
||||
doc=doc,
|
||||
numdocs=numdocs,
|
||||
refs=refs,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def document_ballot_content(request, doc, ballot_id, editable=True):
|
||||
"""Render HTML string with content of ballot page."""
|
||||
all_ballots = list(BallotDocEvent.objects.filter(doc=doc, type="created_ballot").order_by("time"))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django import forms
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.template import RequestContext
|
||||
from django.http import Http404
|
||||
|
||||
from ietf.doc.models import *
|
||||
|
||||
|
@ -44,3 +45,17 @@ def state_help(request, type):
|
|||
"tags": tags,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def relationship_help(request,subset=None):
|
||||
subsets = { "reference": ['refnorm','refinfo','refunk','refold'],
|
||||
"status" : ['tops','tois','tohist','toinf','tobcp','toexp'],
|
||||
}
|
||||
if subset and subset not in subsets:
|
||||
raise Http404()
|
||||
rels = DocRelationshipName.objects.filter(used=True)
|
||||
if subset:
|
||||
rels = rels.filter(slug__in=subsets[subset])
|
||||
return render_to_response("doc/relationship_help.html", {
|
||||
"relations": rels
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
|
|
@ -228,6 +228,8 @@
|
|||
<a href="mailto:{{ doc.name }}@tools.ietf.org?subject=Mail%20regarding%20{{ doc.name }}" rel="nofollow">Email Authors</a>
|
||||
| <a href="{% url ipr_search %}?option=document_search&id={{ doc.name }}" rel="nofollow">IPR Disclosures{% if doc.related_ipr %} ({{doc.related_ipr.count}}){% endif %}</a>
|
||||
| <a href="http://www.fenron.net/~fenner/ietf/deps/index.cgi?dep={{ name }}" rel="nofollow">Dependencies to this document</a>
|
||||
| <a href="{% url doc_references doc.canonical_name %}" rel="nofollow">References</a>
|
||||
| <a href="{% url doc_referenced_by doc.canonical_name %}" rel="nofollow">Referenced By</a>
|
||||
| <a href="http://tools.ietf.org/idnits?url=http://tools.ietf.org/id/{{ doc.filename_with_rev }}" rel="nofollow" target="_blank">Check nits</a>
|
||||
| <a href="/feed/document-changes/{{ name }}/">History feed</a>
|
||||
| <a href="http://www.google.com/search?as_q={{ doc.name }}&as_sitesearch={{ search_archive }}" rel="nofollow" target="_blank">Search Mailing Lists</a>
|
||||
|
|
59
ietf/templates/doc/document_referenced_by.html
Normal file
59
ietf/templates/doc/document_referenced_by.html
Normal file
|
@ -0,0 +1,59 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
References to {{alias_name}}
|
||||
{% endblock %}
|
||||
{% block morecss %}
|
||||
.referencetable {margin-top:1em;}
|
||||
.referenctable .references {width:100%;}
|
||||
.referencetable .references .reference .source {width:30%;}
|
||||
.referencetable .references .reference .title {width:35%;}
|
||||
.referencetable .references .reference .level {width:15%;}
|
||||
.referencetable .references .reference .reftype {width:15%;}
|
||||
.referencetable .references .reference .downref {width:5%;}
|
||||
.reflinks {font-size:80%;float:right;}
|
||||
.showmore {margin-top:1em;}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>References to {{alias_name}}</h1>
|
||||
<div class="info-message-warning">
|
||||
This is an experimental product. These dependencies are extracted using heuristics looking for strings with particular prefixes. Notably, this means that references to I-Ds by title only are not reflected here. If it's really important, please inspect the documents' references sections directly.
|
||||
</div>
|
||||
<div>
|
||||
Showing RFCs and active Internet-Drafts, sorted by <a href="{% url relationship_subset_help subset='reference' %}">reference type</a>, then document name.
|
||||
</div>
|
||||
{% if numdocs %}
|
||||
<div class="showmore">
|
||||
Results restricted to the first 250 of {{ numdocs }} documents. <a href="?full=True">Show All</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="referencetable">
|
||||
<table class="references ietf-table">
|
||||
<tr><th>Document</th><th>Title</th><th>Status</th><th>Reference Type</th><th>Downref</th></tr>
|
||||
{% for ref in refs %}
|
||||
<tr class="reference {% cycle 'evenrow' 'oddrow' %}">
|
||||
<td class="source">
|
||||
{% with ref.source.canonical_name as name %}
|
||||
<a href="{% url doc_view name=name %}">{{name}}</a> {% if ref.target.name != alias_name %}(as {{ref.target.name}}){% endif %} <span class="reflinks">(<a href="{% url doc_references name %}">refs</a>, <a href="{% url doc_referenced_by name %}">refby</a>)</span>
|
||||
{% endwith %}
|
||||
</td>
|
||||
<td class="title">
|
||||
{{ref.source.title}}
|
||||
</td>
|
||||
<td class="level">
|
||||
{% ifequal ref.source.get_state.slug 'rfc' %}
|
||||
{% with ref.source.std_level as lvl %}{% if lvl %}{{lvl}}{% endif %}{%endwith%}
|
||||
{% else %}
|
||||
{% with ref.source.intended_std_level as lvl %}{% if lvl %}{{lvl}}{% endif %}{%endwith%}
|
||||
{% endifequal %}
|
||||
</td>
|
||||
<td class="reftype">
|
||||
{{ref.relationship.name}}
|
||||
</td>
|
||||
<td class="downref">
|
||||
{{ref.is_downref|default:''}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
54
ietf/templates/doc/document_references.html
Normal file
54
ietf/templates/doc/document_references.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
References from {{doc.canonical_name}}
|
||||
{% endblock %}
|
||||
{% block morecss %}
|
||||
.referencetable {margin-top:1em;}
|
||||
.referenctable .references {width:100%;}
|
||||
.referencetable .references .reference .source {width:30%;}
|
||||
.referencetable .references .reference .title {width:35%;}
|
||||
.referencetable .references .reference .level {width:15%;}
|
||||
.referencetable .references .reference .reftype {width:15%;}
|
||||
.referencetable .references .reference .downref {width:5%;}
|
||||
.reflinks {font-size:80%;float:right;}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>References from {{doc.canonical_name}}</h1>
|
||||
<div class="info-message-warning">
|
||||
This is an experimental product. These dependencies are extracted using heuristics looking for strings with particular prefixes. Notably, this means that references to I-Ds by title only are not reflected here. If it's really important, please inspect the documents' references sections directly.
|
||||
</div>
|
||||
<div>
|
||||
Sorted by document name.
|
||||
<a href="{% url relationship_subset_help subset='reference' %}">Reference type help</a>
|
||||
</div>
|
||||
<div class="referencetable">
|
||||
<table class="references ietf-table">
|
||||
<tr><th>Document</th><th>Title</th><th>Status</th><th>Reference Type</th><th>Downref</th></tr>
|
||||
{% for ref in refs %}
|
||||
<tr class="reference {% cycle 'evenrow' 'oddrow' %}">
|
||||
<td class="target">
|
||||
{% with ref.target.name as name %}
|
||||
<a href="{% url doc_view name=name %}">{{name}}</a> <span class="reflinks">(<a href="{% url doc_references name %}">refs</a>, <a href="{% url doc_referenced_by name %}">refby</a>)</span>
|
||||
{% endwith %}
|
||||
</td>
|
||||
<td class="title">
|
||||
{{ref.target.document.title}}
|
||||
</td>
|
||||
<td class="level">
|
||||
{% ifequal ref.target.document.get_state.slug 'rfc' %}
|
||||
{% with ref.target.document.std_level as lvl %}{% if lvl %}{{lvl}}{% endif %}{%endwith%}
|
||||
{% else %}
|
||||
{% with ref.target.document.intended_std_level as lvl %}{% if lvl %}{{lvl}}{% endif %}{%endwith%}
|
||||
{% endifequal %}
|
||||
</td>
|
||||
<td class="reftype">
|
||||
{{ref.relationship.name}}
|
||||
</td>
|
||||
<td class="downref">
|
||||
{{ref.is_downref|default:''}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
29
ietf/templates/doc/relationship_help.html
Normal file
29
ietf/templates/doc/relationship_help.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Document Relationships{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.ietf-table .name { white-space: nowrap; padding-right: 1em; }
|
||||
.ietf-table .desc { max-width: 35em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Document Relationships</h1>
|
||||
|
||||
<table class="ietf-table">
|
||||
<tr>
|
||||
<th>Relationship</th>
|
||||
<th>Description</th>
|
||||
<th>Inverse Relationship</th>
|
||||
</tr>
|
||||
|
||||
{% for rel in relations %}
|
||||
<tr id="{{ rel.slug }}" class="{{ forloop.counter|divisibleby:2|yesno:"evenrow,oddrow" }}">
|
||||
<td class="name">{{ rel.name }}</td>
|
||||
<td class="desc">{{ rel.desc|linebreaksbr }}</td>
|
||||
<td class="revname">{{ rel.revname }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
Loading…
Reference in a new issue