fix: Show rfc documents via document_main view (#5919)

* fix: Fix friendly_state() for drafts in rfc state

* refactor: Change became-rfc to became_rfc for consistency

* refactor: Begin handling RFCs separatly in document_main

WIP

* chore: Hide reviews and conflict reviews for RFCs

* chore: Remove irrelevant fields from rfc doc view

* chore: Remove unused variables

* chore: Remove "Versions" field from document_rfc.html

* chore: Hide "Nits" button for RFC documents
This commit is contained in:
Jennifer Richards 2023-07-05 17:30:20 -03:00 committed by GitHub
parent d87ffb6912
commit 5d9d87897d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 638 additions and 194 deletions

View file

@ -6,7 +6,7 @@ from django.db import migrations
def forward(apps, schema_editor):
"""Point "rfc..." DocAliases at the rfc-type Document
Creates a became-rfc RelatedDocument to preserve the connection between the draft and the rfc.
Creates a became_rfc RelatedDocument to preserve the connection between the draft and the rfc.
"""
DocAlias = apps.get_model("doc", "DocAlias")
Document = apps.get_model("doc", "Document")
@ -22,7 +22,7 @@ def forward(apps, schema_editor):
RelatedDocument.objects.create(
source=aliased_doc,
target=rfc_alias,
relationship_id="became-rfc",
relationship_id="became_rfc",
)
# Now move the alias from the draft to the rfc
rfc_alias.docs.set([rfc])

View file

@ -348,10 +348,9 @@ class DocumentInfo(models.Model):
iesg_state_summary = iesg_state_summary + "::"+"::".join(tag.name for tag in iesg_substate)
if state.slug == "rfc":
# todo check this once became-rfc relationships are actually created
rfcs = self.related_that("became-rfc") # should be only one
rfcs = self.related_that_doc("became_rfc") # should be only one
if len(rfcs) > 0:
rfc = rfcs[0]
rfc = rfcs[0].document
return f"Became RFC {rfc.rfc_number} ({rfc.std_level})"
else:
return "Became RFC"
@ -995,7 +994,7 @@ class Document(DocumentInfo):
This is the rfc publication date for RFCs, and the new-revision date for other documents.
"""
if self.get_state_slug() == "rfc":
if self.is_rfc():
# As of Sept 2022, in ietf.sync.rfceditor.update_docs_from_rfc_index() `published_rfc` events are
# created with a timestamp whose date *in the PST8PDT timezone* is the official publication date
# assigned by the RFC editor.

View file

@ -180,9 +180,9 @@ def interesting_doc_relations(doc):
else:
raise TypeError("Expected this method to be called with a Document or DocHistory object")
that_relationships = STATUSCHANGE_RELATIONS + ('conflrev', 'replaces', 'possibly_replaces', 'updates', 'obs')
that_relationships = STATUSCHANGE_RELATIONS + ('conflrev', 'replaces', 'possibly_replaces', 'updates', 'obs', 'became_rfc')
that_doc_relationships = ('replaces', 'possibly_replaces', 'updates', 'obs')
that_doc_relationships = ('replaces', 'possibly_replaces', 'updates', 'obs', 'became_rfc')
# TODO: This returns the relationships in database order, which may not be the order we want to display them in.
interesting_relations_that = cls.objects.filter(target__docs=target, relationship__in=that_relationships).select_related('source')
@ -240,7 +240,137 @@ def document_main(request, name, rev=None, document_html=False):
# specific document types
if doc.type_id == "draft":
if doc.is_rfc():
split_content = request.COOKIES.get("full_draft", settings.USER_PREFERENCE_DEFAULTS["full_draft"]) == "off"
if request.GET.get('include_text') == "0":
split_content = True
elif request.GET.get('include_text') == "1":
split_content = False
else:
pass
interesting_relations_that, interesting_relations_that_doc = interesting_doc_relations(doc)
can_edit = has_role(request.user, ("Area Director", "Secretariat"))
can_edit_authors = has_role(request.user, ("Secretariat"))
stream_slugs = StreamName.objects.values_list("slug", flat=True)
# For some reason, AnonymousUser has __iter__, but is not iterable,
# which causes problems in the filter() below. Work around this:
if request.user.is_authenticated:
roles = Role.objects.filter(group__acronym__in=stream_slugs, person__user=request.user)
roles = group_features_role_filter(roles, request.user.person, 'docman_roles')
else:
roles = []
can_change_stream = bool(can_edit or roles)
rfc_aliases = [prettify_std_name(a) for a in aliases
if a.startswith("fyi") or a.startswith("std") or a.startswith("bcp")]
file_urls, found_types = build_file_urls(doc)
content = doc.text_or_error() # pyflakes:ignore
content = markup_txt.markup(maybe_split(content, split=split_content))
if not found_types:
content = "This RFC is not currently available online."
split_content = False
elif "txt" not in found_types:
content = "This RFC is not available in plain text format."
split_content = False
# mailing list search archive
search_archive = "www.ietf.org/mail-archive/web/"
if doc.stream_id == "ietf" and group.type_id == "wg" and group.list_archive:
search_archive = group.list_archive
search_archive = quote(search_archive, safe="~")
# status changes
status_changes = []
proposed_status_changes = []
for r in interesting_relations_that.filter(relationship__in=STATUSCHANGE_RELATIONS):
state_slug = r.source.get_state_slug()
if state_slug in ('appr-sent', 'appr-pend'):
status_changes.append(r)
elif state_slug in ('needshep','adrev','iesgeval','defer','appr-pr'):
proposed_status_changes.append(r)
else:
pass
presentations = doc.future_presentations()
augment_docs_and_user_with_user_info([doc], request.user)
exp_comment = doc.latest_event(IanaExpertDocEvent,type="comment")
iana_experts_comment = exp_comment and exp_comment.desc
# Do not show the Auth48 URL in the "Additional URLs" section
additional_urls = doc.documenturl_set.exclude(tag_id='auth48')
html = None
js = None
css = None
diff_revisions = None
simple_diff_revisions = None
if document_html:
diff_revisions=get_diff_revisions(request, name, doc if isinstance(doc,Document) else doc.doc)
simple_diff_revisions = [t[1] for t in diff_revisions if t[0] == doc.name]
simple_diff_revisions.reverse()
if rev and rev != doc.rev:
# No DocHistory was found matching rev - snapshot will be false
# and doc will be a Document object, not a DocHistory
snapshot = True
doc = doc.fake_history_obj(rev)
else:
html = doc.html_body()
if request.COOKIES.get("pagedeps") == "inline":
js = Path(finders.find("ietf/js/document_html.js")).read_text()
css = Path(finders.find("ietf/css/document_html_inline.css")).read_text()
if html:
css += Path(finders.find("ietf/css/document_html_txt.css")).read_text()
# todo replace document_html?
return render(request, "doc/document_rfc.html" if document_html is False else "doc/document_html.html",
dict(doc=doc,
document_html=document_html,
css=css,
js=js,
html=html,
group=group,
top=top,
name=doc.name,
content=content,
split_content=split_content,
revisions=simple_diff_revisions if document_html else revisions,
snapshot=snapshot,
latest_rev=latest_rev,
can_edit=can_edit,
can_edit_authors=can_edit_authors,
can_change_stream=can_change_stream,
rfc_number=doc.rfc_number,
draft_name=doc.name,
updates=interesting_relations_that_doc.filter(relationship="updates"),
updated_by=interesting_relations_that.filter(relationship="updates"),
obsoletes=interesting_relations_that_doc.filter(relationship="obs"),
obsoleted_by=interesting_relations_that.filter(relationship="obs"),
status_changes=status_changes,
proposed_status_changes=proposed_status_changes,
rfc_aliases=rfc_aliases,
has_errata=doc.pk and doc.tags.filter(slug="errata"), # doc.pk == None if using a fake_history_obj
file_urls=file_urls,
additional_urls=additional_urls,
rfc_editor_state=doc.get_state("draft-rfceditor"),
iana_review_state=doc.get_state("draft-iana-review"),
iana_action_state=doc.get_state("draft-iana-action"),
iana_experts_state=doc.get_state("draft-iana-experts"),
iana_experts_comment=iana_experts_comment,
search_archive=search_archive,
presentations=presentations,
diff_revisions=diff_revisions
))
elif doc.type_id == "draft":
split_content = request.COOKIES.get("full_draft", settings.USER_PREFERENCE_DEFAULTS["full_draft"]) == "off"
if request.GET.get('include_text') == "0":
split_content = True
@ -278,43 +408,13 @@ def document_main(request, name, rev=None, document_html=False):
is_author = request.user.is_authenticated and doc.documentauthor_set.filter(person__user=request.user).exists()
can_view_possibly_replaces = can_edit_replaces or is_author
rfc_number = name[3:] if name.startswith("rfc") else None
draft_name = None
for a in aliases:
if a.startswith("draft"):
draft_name = a
rfc_aliases = [prettify_std_name(a) for a in aliases
if a.startswith("fyi") or a.startswith("std") or a.startswith("bcp")]
latest_revision = None
# Workaround to allow displaying last rev of draft that became rfc as a draft
# This should be unwound when RFCs become their own documents.
if snapshot:
doc.name = doc.doc.name
name = doc.doc.name
else:
name = doc.name
file_urls, found_types = build_file_urls(doc)
if not snapshot and doc.get_state_slug() == "rfc":
# content
content = doc.text_or_error() # pyflakes:ignore
content = markup_txt.markup(maybe_split(content, split=split_content))
content = doc.text_or_error() # pyflakes:ignore
content = markup_txt.markup(maybe_split(content, split=split_content))
if not snapshot and doc.get_state_slug() == "rfc":
if not found_types:
content = "This RFC is not currently available online."
split_content = False
elif "txt" not in found_types:
content = "This RFC is not available in plain text format."
split_content = False
else:
latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision")
latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision")
# ballot
iesg_ballot_summary = None
@ -494,7 +594,7 @@ def document_main(request, name, rev=None, document_html=False):
augment_docs_and_user_with_user_info([doc], request.user)
published = doc.latest_event(type="published_rfc")
published = doc.latest_event(type="published_rfc") # todo rethink this now that published_rfc is on rfc
started_iesg_process = doc.latest_event(type="started_iesg_process")
review_assignments = review_assignments_to_list_for_docs([doc]).get(doc.name, [])
@ -512,12 +612,6 @@ def document_main(request, name, rev=None, document_html=False):
# Do not show the Auth48 URL in the "Additional URLs" section
additional_urls = doc.documenturl_set.exclude(tag_id='auth48')
# Stream description passing test
if doc.stream != None:
stream_desc = doc.stream.desc
else:
stream_desc = "(None)"
html = None
js = None
css = None
@ -548,12 +642,11 @@ def document_main(request, name, rev=None, document_html=False):
html=html,
group=group,
top=top,
name=name,
name=doc.name,
content=content,
split_content=split_content,
revisions=simple_diff_revisions if document_html else revisions,
snapshot=snapshot,
stream_desc=stream_desc,
latest_revision=latest_revision,
latest_rev=latest_rev,
can_edit=can_edit,
@ -571,8 +664,7 @@ def document_main(request, name, rev=None, document_html=False):
can_request_review=can_request_review,
can_submit_unsolicited_review_for_teams=can_submit_unsolicited_review_for_teams,
rfc_number=rfc_number,
draft_name=draft_name,
draft_name=doc.name,
telechat=telechat,
iesg_ballot_summary=iesg_ballot_summary,
submission=submission,
@ -589,7 +681,7 @@ def document_main(request, name, rev=None, document_html=False):
conflict_reviews=conflict_reviews,
status_changes=status_changes,
proposed_status_changes=proposed_status_changes,
rfc_aliases=rfc_aliases,
# rfc_aliases=rfc_aliases,
has_errata=doc.pk and doc.tags.filter(slug="errata"), # doc.pk == None if using a fake_history_obj
published=published,
file_urls=file_urls,
@ -618,7 +710,7 @@ def document_main(request, name, rev=None, document_html=False):
diff_revisions=diff_revisions
))
if doc.type_id == "charter":
elif doc.type_id == "charter":
content = doc.text_or_error() # pyflakes:ignore
content = markup_txt.markup(content)
@ -655,7 +747,7 @@ def document_main(request, name, rev=None, document_html=False):
can_manage=can_manage,
))
if doc.type_id == "bofreq":
elif doc.type_id == "bofreq":
content = markdown.markdown(doc.text_or_error())
editors = bofreq_editors(doc)
responsible = bofreq_responsible(doc)
@ -675,7 +767,7 @@ def document_main(request, name, rev=None, document_html=False):
editor_can_manage=editor_can_manage,
))
if doc.type_id == "conflrev":
elif doc.type_id == "conflrev":
filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev)
pathname = os.path.join(settings.CONFLICT_REVIEW_PATH,filename)
@ -705,7 +797,7 @@ def document_main(request, name, rev=None, document_html=False):
approved_states=('appr-reqnopub-pend','appr-reqnopub-sent','appr-noprob-pend','appr-noprob-sent'),
))
if doc.type_id == "statchg":
elif doc.type_id == "statchg":
filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev)
pathname = os.path.join(settings.STATUS_CHANGE_PATH,filename)
@ -739,7 +831,7 @@ def document_main(request, name, rev=None, document_html=False):
sorted_relations=sorted_relations,
))
if doc.type_id in ("slides", "agenda", "minutes", "bluesheets", "procmaterials",):
elif doc.type_id in ("slides", "agenda", "minutes", "bluesheets", "procmaterials",):
can_manage_material = can_manage_materials(request.user, doc.group)
presentations = doc.future_presentations()
if doc.uploaded_filename:
@ -795,7 +887,7 @@ def document_main(request, name, rev=None, document_html=False):
))
if doc.type_id == "review":
elif doc.type_id == "review":
basename = "{}.txt".format(doc.name)
pathname = os.path.join(doc.get_file_path(), basename)
content = get_unicode_document_content(basename, pathname)
@ -821,7 +913,7 @@ def document_main(request, name, rev=None, document_html=False):
assignments=assignments,
))
if doc.type_id in ("chatlog", "polls"):
elif doc.type_id in ("chatlog", "polls"):
if isinstance(doc,DocHistory):
session = doc.doc.sessionpresentation_set.last().session
else:
@ -1084,9 +1176,9 @@ def document_history(request, name):
# Get related docs whose history should be linked
if doc.type_id == "draft":
related = doc.related_that_doc("became-rfc")
related = doc.related_that_doc("became_rfc")
elif doc.type_id == "rfc":
related = doc.related_that("became-rfc")
related = doc.related_that("became_rfc")
else:
related = []

View file

@ -9919,7 +9919,7 @@
"used": true
},
"model": "name.docrelationshipname",
"pk": "became-rfc"
"pk": "became_rfc"
},
{
"fields": {

View file

@ -14,7 +14,7 @@ def forward(apps, schema_editor):
DocRelationshipName = apps.get_model("name", "DocRelationshipName")
DocRelationshipName.objects.get_or_create(
slug="became-rfc",
slug="became_rfc",
name="became RFC",
used=True,
revname="came from draft",

View file

@ -11,15 +11,15 @@
<th scope="row">{% if document_html %}Document type{% else %}Type{% endif %}</th>
<td class="edit"></td>
<td>
{% if doc.get_state_slug == "rfc" and not snapshot %}
{% if doc.is_rfc %}
<span class="text-success">RFC
{% if not document_html %}
- {{ doc.std_level }}
{% else %}
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">{{ doc.std_level }}</span>
{% endif %}
{% else %}
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">{{ doc.std_level }}</span>
{% endif %}
</span>
{% if published %}
{% if doc.is_rfc %}
{% if document_html %}<br>{% else %}({% endif %}{{ doc.pub_date|date:"F Y" }}{% if not document_html %}){% endif %}
{% else %}
<span class="text-muted">(Publication date unknown)</span>
@ -132,91 +132,93 @@
</td>
</tr>
{% endif %}
{% if replaces or not document_html and can_edit_stream_info %}
<tr>
<td></td>
<th scope="row">Replaces</th>
<td class="edit">
{% if can_edit_stream_info and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.replaces' name=doc.name %}">Edit</a>
{% endif %}
</td>
<td>
{% if replaces %}
{% if document_html %}
{{ replaces|urlize_related_target_list:document_html|join:"<br>" }}
{% else %}
{{ replaces|urlize_related_target_list:document_html|join:", " }}
{% endif %}
{% else %}
<span class="text-muted">(None)</span>
{% endif %}
</td>
</tr>
{% endif %}
{% if replaced_by %}
<tr>
<td></td>
<th scope="row">
Replaced by
</th>
<td class="edit">
</td>
<td>
{% if document_html %}
{{ replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
{% else %}
{{ replaced_by|urlize_related_source_list:document_html|join:", " }}
{% endif %}
</td>
</tr>
{% endif %}
{% if can_view_possibly_replaces %}
{% if possibly_replaces %}
{% if not doc.is_rfc %}
{% if replaces or not document_html and can_edit_stream_info %}
<tr>
<td></td>
<th scope="row">
Possibly Replaces
</th>
<th scope="row">Replaces</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
{% if can_edit_stream_info and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">
Edit
</a>
href="{% url 'ietf.doc.views_draft.replaces' name=doc.name %}">Edit</a>
{% endif %}
</td>
<td>
{% if document_html %}
{{ possibly_replaces|urlize_related_target_list:document_html|join:"<br>" }}
{% if replaces %}
{% if document_html %}
{{ replaces|urlize_related_target_list:document_html|join:"<br>" }}
{% else %}
{{ replaces|urlize_related_target_list:document_html|join:", " }}
{% endif %}
{% else %}
{{ possibly_replaces|urlize_related_target_list:document_html|join:", " }}
<span class="text-muted">(None)</span>
{% endif %}
</td>
</tr>
{% endif %}
{% if possibly_replaced_by %}
{% if replaced_by %}
<tr>
<td></td>
<th scope="row">
Possibly Replaced By
Replaced by
</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
{% comment %}<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">Edit</a>{% endcomment %}
{% endif %}
</td>
<td>
{% if document_html %}
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
{{ replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
{% else %}
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:", " }}
{{ replaced_by|urlize_related_source_list:document_html|join:", " }}
{% endif %}
</td>
</tr>
{% endif %}
{% if can_view_possibly_replaces %}
{% if possibly_replaces %}
<tr>
<td></td>
<th scope="row">
Possibly Replaces
</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if document_html %}
{{ possibly_replaces|urlize_related_target_list:document_html|join:"<br>" }}
{% else %}
{{ possibly_replaces|urlize_related_target_list:document_html|join:", " }}
{% endif %}
</td>
</tr>
{% endif %}
{% if possibly_replaced_by %}
<tr>
<td></td>
<th scope="row">
Possibly Replaced By
</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
{% comment %}<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">Edit</a>{% endcomment %}
{% endif %}
</td>
<td>
{% if document_html %}
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
{% else %}
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:", " }}
{% endif %}
</td>
</tr>
{% endif %}
{% endif %}
{% endif %}
<tr>
<td></td>
@ -231,15 +233,15 @@ href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">E
</a>
{% endif %}
</td>
<td {% if stream_desc == "(None)" %}class="text-muted"{%endif%}>
{% if stream_desc != "(None)" %}
<td {% if doc.stream is None %}class="text-muted"{%endif%}>
{% if doc.stream is not None %}
{% if doc.stream.name|lower in 'iab,irtf,ise,editorial' %}
<a href="{% url 'ietf.group.views.stream_documents' acronym=doc.stream.name|lower %}">
{% endif %}
{% if document_html %}
{% if doc.stream.name|lower in 'iab,ietf,irtf' %}
<img alt="{{ doc.stream.name|upper }} Logo"
title="{{ stream_desc }}"
title="{{ doc.stream.desc }}"
class="w-25 mt-1"
{% if doc.stream.name|lower == 'iab' %}
src="{% static 'ietf/images/iab-logo.svg' %}"
@ -250,20 +252,20 @@ href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">E
{% endif %}
>
{% else %}
{{ stream_desc }}
{{ doc.stream.desc }}
{% endif %}
{% else %}
{{ stream_desc }}
{{ doc.stream.desc }}
{% endif %}
{% if doc.stream.name|lower in 'iab,irtf,ise,editorial' %}
</a>
{% endif %}
{% else %}
{{ stream_desc }}
(None)
{% endif %}
</td>
</tr>
{% if doc.get_state_slug != "rfc" and not snapshot %}
{% if not doc.is_rfc and not snapshot %}
<tr>
<td></td>
<th scope="row">
@ -339,67 +341,69 @@ href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">E
</tr>
{% endif %}
{% endfor %}
{% if review_assignments or can_request_review %}
<tr>
<td></td>
<th scope="row">
Reviews
</th>
<td class="edit">
</td>
<td>
{% for review_assignment in review_assignments %}
{% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev %}
{% endfor %}
{% if no_review_from_teams %}
{% for team in no_review_from_teams %}
{{ team.acronym.upper }}{% if not forloop.last %},{% endif %}
{% endfor %}
will not review this version
{% endif %}
{% if can_request_review or can_submit_unsolicited_review_for_teams %}
<div {% if review_assignments or no_review_from_teams %}class="mt-3"{% endif %}>
{% if can_request_review %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.request_review" doc.name %}">
<i class="bi bi-check-circle">
</i>
Request review
</a>
{% if not doc.is_rfc %}{# do not show reviews or conflict_reviews for RFCs, even if present #}
{% if review_assignments or can_request_review %}
<tr>
<td></td>
<th scope="row">
Reviews
</th>
<td class="edit">
</td>
<td>
{% for review_assignment in review_assignments %}
{% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev %}
{% endfor %}
{% if no_review_from_teams %}
{% for team in no_review_from_teams %}
{{ team.acronym.upper }}{% if not forloop.last %},{% endif %}
{% endfor %}
will not review this version
{% endif %}
{% if can_submit_unsolicited_review_for_teams|length == 1 %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.complete_review" doc.name can_submit_unsolicited_review_for_teams.0.acronym %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% elif can_submit_unsolicited_review_for_teams %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.submit_unsolicited_review_choose_team" doc.name %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% if can_request_review or can_submit_unsolicited_review_for_teams %}
<div {% if review_assignments or no_review_from_teams %}class="mt-3"{% endif %}>
{% if can_request_review %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.request_review" doc.name %}">
<i class="bi bi-check-circle">
</i>
Request review
</a>
{% endif %}
{% if can_submit_unsolicited_review_for_teams|length == 1 %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.complete_review" doc.name can_submit_unsolicited_review_for_teams.0.acronym %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% elif can_submit_unsolicited_review_for_teams %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.submit_unsolicited_review_choose_team" doc.name %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
</td>
</tr>
{% endif %}
{% if conflict_reviews %}
<tr>
<td></td>
<th scope="row">
IETF conflict review
</th>
<td class="edit">
</td>
<td>
{{ conflict_reviews|join:", "|urlize_ietf_docs }}
</td>
</tr>
{% endif %}
</td>
</tr>
{% endif %}
{% if conflict_reviews %}
<tr>
<td></td>
<th scope="row">
IETF conflict review
</th>
<td class="edit">
</td>
<td>
{{ conflict_reviews|join:", "|urlize_ietf_docs }}
</td>
</tr>
{% endif %}
{% endif %}
{% endif %}
{% with doc.docextresource_set.all as resources %}
{% if resources or doc.group and doc.group.list_archive or can_edit_stream_info or can_edit_individual %}

View file

@ -0,0 +1,349 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2016-2020, All Rights Reserved #}
{% load origin %}
{% load static %}
{% load ietf_filters %}
{% load person_filters %}
{% load textfilters %}
{% block html_attrs %}prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#"{% endblock %}
{% block pagehead %}
{% include "doc/opengraph.html" %}
<link rel="alternate"
type="application/atom+xml"
title="Document changes"
href="/feed/document-changes/{{ name }}/">
<meta name="description"
content="{{ doc.title }} {% if doc.get_state_slug == 'rfc' and not snapshot %}(RFC {{ rfc_number }}{% if published %}, {{ doc.pub_date|date:'F Y' }}{% endif %}{% if obsoleted_by %}; obsoleted by {% for rel in obsoleted_by %}{{ rel.source.canonical_name|prettystdname}}{% if not forloop.last%}, {% endif %}{% endfor %}{% endif %}){% endif %}">
{% endblock %}
{% block morecss %}.inline { display: inline; }{% endblock %}
{% block title %}
{% if doc.get_state_slug == "rfc" and not snapshot %}
RFC {{ rfc_number }} - {{ doc.title }}
{% else %}
{{ name }}-{{ doc.rev }} - {{ doc.title }}
{% endif %}
{% endblock %}
{% block content %}
{% origin %}
{{ top|safe }}
<div id="timeline"></div>
{% if doc.rev != latest_rev %}
<div class="alert alert-warning my-3">The information below is for an old version of the document.</div>
{% else %}
{% if doc.get_state_slug == "rfc" and snapshot %}
<div class="alert alert-warning my-3">
The information below is for an old version of the document that is already published as an RFC.
</div>
{% endif %}
{% endif %}
<table class="table table-sm table-borderless">
{% include "doc/document_info.html" %}
<tbody class="meta border-top">
{% if milestones %}
<tr>
<td></td>
<th scope="row">
Associated
{% if doc.stream_id == 'ietf' %}
WG
{% else %}
{{ doc.stream }}
{% endif %} milestone{{ milestones|pluralize }}</th>
<td class="edit"></td>
<td>
<dl class="row">
{% for m in milestones %}
<dt class="col-sm-2 my-0">{{ m.due|date:"M Y" }}</dt>
<dd class="col-sm-10 my-0">{{ m.desc }}</dd>
{% endfor %}
</dl>
</td>
</tr>
{% endif %}
</tbody>
{% if doc.stream_id != 'iab' %}
<tbody class="meta border-top">
<tr>
<th scope="row">
IESG
</th>
<th scope="row">
Responsible AD
</th>
<td class="edit">
{% if can_edit %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.edit_ad' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if doc.ad %}
{% person_link doc.ad %}
{% else %}
<span class="text-muted">
(None)
</span>
{% endif %}
</td>
</tr>
<tr>
<td></td>
<th scope="row">
Send notices to
</th>
<td class="edit">
{% if can_edit_notify and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_doc.edit_notify' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if doc.notify %}
{{ doc.notify|linkify }}
{% else %}
<span class="text-muted">
(None)
</span>
{% endif %}
</td>
</tr>
</tbody>
{% endif %}
{% if rfc_editor_state %}
<tbody class="meta border-top">
<tr>
<th scope="row">
RFC Editor
</th>
<th scope="row">
<a href="{% url "ietf.help.views.state" doc=doc.type.slug type="rfceditor" %}">
RFC Editor state
</a>
</th>
<td class="edit">
</td>
<td>
{{ rfc_editor_state }}
</td>
</tr>
<tr>
<td></td>
<th scope="row">
Details
</th>
<td class="edit">
</td>
<td>
<div>
<a href="https://www.rfc-editor.org/queue2.html#{{ doc.name }}">
Publication queue entry
</a>
</div>
{% if rfc_editor_auth48_url %}
<div>
<a href="{{ rfc_editor_auth48_url }}">
Auth48 status
</a>
</div>
{% endif %}
</td>
</tr>
</tbody>
{% endif %}
</table>
<div class="buttonlist">
<a class="btn btn-primary btn-sm"
href="mailto:{{ doc.name }}@ietf.org?subject=Mail%20regarding%20{{ doc.name }}">
<i class="bi bi-envelope">
</i>
Email authors
</a>
{% if doc.group.type.slug == 'wg' or doc.group.type.slug == 'rg' %}
<a class="btn btn-primary btn-sm"
href="mailto:{{ doc.group.list_email }}?subject=Mail%20regarding%20{{ doc.name }}">
<i class="bi bi-envelope">
</i>
Email {{ doc.group.type }}
</a>
{% endif %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.ipr.views.search" %}?submit=draft&amp;id={{ doc.name }}"
rel="nofollow">
<i class="bi bi-lightning">
</i>
IPR
{% if doc.related_ipr %}
<span class="badge rounded-pill">
{{ doc.related_ipr|length }}
</span>
{% endif %}
</a>
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_doc.document_references' doc.canonical_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' doc.canonical_name %}"
rel="nofollow">
<i class="bi bi-arrow-right">
</i>
Referenced by
</a>
{# document_draft shows Nits here, excluded for RFCs #}
<div class="dropdown inline">
<button class="btn btn-primary btn-sm dropdown-toggle"
type="button"
id="ddSearchMenu"
data-bs-toggle="dropdown"
aria-expanded="true">
<i class="bi bi-search">
</i>
Search lists
</button>
<ul class="dropdown-menu" role="menu">
<li role="presentation">
<a class="dropdown-item"
href="https://mailarchive.ietf.org/arch/search?q=%22{{ doc.name }}%22"
rel="nofollow"
target="_blank">
IETF Mail Archive
</a>
</li>
<li role="presentation">
<a class="dropdown-item"
href="https://www.google.com/search?as_q={{ doc.name }}&amp;as_sitesearch={{ search_archive }}"
rel="nofollow"
target="_blank">
Google
</a>
</li>
{% if user|has_role:"Area Director" %}
<li role="presentation">
<a class="dropdown-item"
href="https://www.iesg.org/bin/c5i?mid=6&amp;rid=77&amp;target={{ doc.name }}"
rel="nofollow"
target="_blank">
ARO
</a>
</li>
{% endif %}
</ul>
</div>
{% if user.is_authenticated %}
<a class="btn btn-primary btn-sm track-untrack-doc {% if not doc.tracked_in_personal_community_list %}hide{% endif %}"
href="{% url "ietf.community.views.untrack_document" username=user.username name=doc.name %}"
title="Remove from your personal I-D list">
<i class="bi bi-bookmark-check-fill">
</i>
Untrack
</a>
<a class="btn btn-primary btn-sm track-untrack-doc {% if doc.tracked_in_personal_community_list %}hide{% endif %}"
href="{% url "ietf.community.views.track_document" username=user.username name=doc.name %}"
title="Add to your personal I-D list">
<i class="bi bi-bookmark">
</i>
Track
</a>
{% endif %}
{% if user.review_teams %}
<a class="btn btn-primary btn-sm review-wish-add-remove-doc ajax {% if not doc.has_review_wish %}hide{% endif %}"
href="{% url "ietf.doc.views_review.review_wishes_remove" name=doc.name %}?next={{ request.get_full_path|urlencode }}"
title="Remove from your review wishes for all teams">
<i class="bi bi-chat-left-heart-fill">
</i>
Remove review wishes
</a>
<a class="btn btn-primary btn-sm review-wish-add-remove-doc {% if user.review_teams|length_is:"1" %}ajax {% endif %}{% if doc.has_review_wish %}hide{% endif %}"
href="{% url "ietf.doc.views_review.review_wish_add" name=doc.name %}?next={{ request.get_full_path|urlencode }}"
title="Add to your review wishes">
<i class="bi bi-chat-left-heart">
</i>
Add review wish
</a>
{% endif %}
{% if can_edit and iesg_state.slug != 'idexists' %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_ballot.lastcalltext' name=doc.name %}">
Last call text
</a>
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_ballot.ballot_writeupnotes' name=doc.name %}">
Ballot text
</a>
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_ballot.ballot_approvaltext' name=doc.name %}">
Announcement text
</a>
{% endif %}
{% if actions %}
{% for label, url in actions %}
<a class="btn btn-primary btn-sm" href="{{ url }}">
{{ label|capfirst_allcaps }}
</a>
{% endfor %}
{% endif %}
</div>
{% if doc.get_state_slug == "active" or doc.get_state_slug == "rfc" %}
<div class="card mt-5">
<div class="card-header">
{% if doc.get_state_slug == "rfc" and not snapshot %}
RFC {{ rfc_number }}
{% else %}
{{ name }}-{{ doc.rev }}
{% endif %}
</div>
<div class="card-body">
<pre>{{ content|sanitize|safe|default:"(Unavailable)" }}</pre>
</div>
</div>
{% if split_content %}
<a class="btn btn-primary my-3" href="?include_text=1">
<i class="bi bi-caret-down">
</i>
Show full document
</a>
{% endif %}
{% else %}
<div class="card border-warning mt-5">
<div class="card-header bg-warning">
<p><b>This Internet-Draft is no longer active. A copy of
the expired Internet-Draft is available in these formats:</b></p>
{% include "doc/document_format_buttons.html" %}
</div>
<div class="card-body">
<p class="h5 card-title">
Abstract
</p>
<p class="card-text">
{{ doc.abstract }}
</p>
<p class="h5 card-title">
Authors
</p>
<p class="card-text">
{% for author in doc.documentauthor_set.all %}
{% person_link author.person %}
{% if not forloop.last %}<br>{% endif %}
{% endfor %}
</p>
<p class="text-muted card-text">
(Note: The e-mail addresses provided for the authors of this Internet-Draft may no longer be valid.)
</p>
</div>
</div>
{% endif %}
{% endblock %}
{% block js %}
<script src="{% static 'ietf/js/d3.js' %}">
</script>
<script src="{% static 'ietf/js/document_timeline.js' %}">
</script>
{% endblock %}