diff --git a/ietf/api/views.py b/ietf/api/views.py index b9ff1ed34..df7fdb2c8 100644 --- a/ietf/api/views.py +++ b/ietf/api/views.py @@ -328,7 +328,7 @@ def rfcdiff_latest_json(request, name, rev=None): response = dict() condition, document, history, found_rev = find_doc_for_rfcdiff(name, rev) if document.type_id == "rfc": - draft = next(iter(document.related_that('became_rfc')), None) + draft = document.came_from_draft() if condition == 'no such document': raise Http404 elif condition in ('historic version', 'current version'): diff --git a/ietf/doc/factories.py b/ietf/doc/factories.py index 23dbda8cc..32e87f195 100644 --- a/ietf/doc/factories.py +++ b/ietf/doc/factories.py @@ -51,7 +51,11 @@ class BaseDocumentFactory(factory.django.DjangoModelFactory): def name(self, n): return draft_name_generator(self.type_id,self.group,n) - newrevisiondocevent = factory.RelatedFactory('ietf.doc.factories.NewRevisionDocEventFactory','doc') + @factory.post_generation + def newrevisiondocevent(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument + if create: + if obj.type_id != "rfc": + NewRevisionDocEventFactory(doc=obj) @factory.post_generation def states(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument @@ -106,6 +110,7 @@ class DocumentFactory(BaseDocumentFactory): class RfcFactory(BaseDocumentFactory): type_id = "rfc" + rev = "" rfc_number = factory.Sequence(lambda n: n + 1000) name = factory.LazyAttribute(lambda o: f"rfc{o.rfc_number:d}") expires = None diff --git a/ietf/doc/management/commands/generate_draft_aliases.py b/ietf/doc/management/commands/generate_draft_aliases.py index b377fdda1..6d42a66a1 100755 --- a/ietf/doc/management/commands/generate_draft_aliases.py +++ b/ietf/doc/management/commands/generate_draft_aliases.py @@ -130,7 +130,7 @@ class Command(BaseCommand): for draft in interesting_drafts.distinct().iterator(): # Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS if draft.get_state_slug()=="rfc": - rfc = next(iter(draft.related_that_doc("became_rfc")), None) + rfc = draft.became_rfc() log.assertion("rfc is not None") if rfc.latest_event(type='published_rfc').time < show_since: continue diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 632d6a827..ebc0a575e 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -198,17 +198,28 @@ class DocumentInfo(models.Model): self._cached_file_name = os.path.join(self.get_file_path(), self.get_base_name()) return self._cached_file_name - def revisions(self): + + def revisions_by_dochistory(self): revisions = [] - doc = self.doc if isinstance(self, DocHistory) else self - for e in doc.docevent_set.filter(type='new_revision').distinct(): - if e.rev and not e.rev in revisions: - revisions.append(e.rev) - if not doc.rev in revisions: - revisions.append(doc.rev) - revisions.sort() + if self.type_id != "rfc": + for h in self.history_set.order_by("time", "id"): + if h.rev and not h.rev in revisions: + revisions.append(h.rev) + if not self.rev in revisions: + revisions.append(self.rev) return revisions + def revisions_by_newrevisionevent(self): + revisions = [] + if self.type_id != "rfc": + doc = self.doc if isinstance(self, DocHistory) else self + for e in doc.docevent_set.filter(type='new_revision').distinct(): + if e.rev and not e.rev in revisions: + revisions.append(e.rev) + if not doc.rev in revisions: + revisions.append(doc.rev) + revisions.sort() + return revisions def get_href(self, meeting=None): return self._get_ref(meeting=meeting,meeting_doc_refs=settings.MEETING_DOC_HREFS) @@ -654,6 +665,15 @@ class DocumentInfo(models.Model): source__type__slug="rfc" ) + def became_rfc(self): + doc = self if isinstance(self, Document) else self.doc + return next(iter(doc.related_that_doc("became_rfc")), None) + + def came_from_draft(self): + doc = self if isinstance(self, Document) else self.doc + return next(iter(doc.related_that("became_rfc")), None) + + class Meta: abstract = True diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 05e721034..d6c432746 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -2883,3 +2883,30 @@ class CanRequestConflictReviewTests(TestCase): r = self.client.get(url) self.assertContains(r, target_string) +class DocInfoMethodsTests(TestCase): + + def test_became_rfc(self): + draft = WgDraftFactory() + rfc = WgRfcFactory() + draft.relateddocument_set.create(relationship_id="became_rfc",target=rfc) + self.assertEqual(draft.became_rfc(), rfc) + self.assertEqual(rfc.came_from_draft(), draft) + + charter = CharterFactory() + self.assertIsNone(charter.became_rfc()) + self.assertIsNone(charter.came_from_draft()) + + def test_revisions(self): + draft = WgDraftFactory(rev="09",create_revisions=range(0,10)) + self.assertEqual(draft.revisions_by_dochistory(),[f"{i:02d}" for i in range(0,10)]) + self.assertEqual(draft.revisions_by_newrevisionevent(),[f"{i:02d}" for i in range(0,10)]) + rfc = WgRfcFactory() + self.assertEqual(rfc.revisions_by_newrevisionevent(),[]) + self.assertEqual(rfc.revisions_by_dochistory(),[]) + + draft.history_set.filter(rev__lt="08").delete() + draft.docevent_set.filter(newrevisiondocevent__rev="05").delete() + 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)]]) + + diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index ef062cf1d..ae1d32ffa 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -197,16 +197,11 @@ def document_main(request, name, rev=None, document_html=False): # take care of possible redirections if document_html is False and rev is None: - became_rfc = next(iter(doc.related_that_doc("became_rfc")), None) + became_rfc = doc.became_rfc() if became_rfc: return redirect("ietf.doc.views_doc.document_main", name=became_rfc.name) - - revisions = [] - for h in doc.history_set.order_by("time", "id"): - if h.rev and not h.rev in revisions: - revisions.append(h.rev) - if not doc.rev in revisions: - revisions.append(doc.rev) + + revisions = doc.revisions_by_dochistory() latest_rev = doc.rev snapshot = False @@ -214,12 +209,16 @@ def document_main(request, name, rev=None, document_html=False): gh = None if rev: # find the entry in the history + debug.show('doc.name') for h in doc.history_set.order_by("-time"): if rev == h.rev: snapshot = True doc = h break + debug.show('doc.name') + + if not snapshot and document_html is False: return redirect('ietf.doc.views_doc.document_main', name=name) @@ -239,7 +238,6 @@ def document_main(request, name, rev=None, document_html=False): if telechat and (not telechat.telechat_date or telechat.telechat_date < date_today(settings.TIME_ZONE)): telechat = None - # specific document types if doc.type_id == "rfc": split_content = request.COOKIES.get("full_draft", settings.USER_PREFERENCE_DEFAULTS["full_draft"]) == "off" @@ -302,7 +300,7 @@ def document_main(request, name, rev=None, document_html=False): 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) + diff_revisions=get_diff_revisions(request, name, doc) simple_diff_revisions = [t[1] for t in diff_revisions if t[0] == doc.name] simple_diff_revisions.reverse() html = doc.html_body() @@ -311,10 +309,8 @@ def document_main(request, name, rev=None, document_html=False): 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() - draft_that_became_rfc = None - became_rfc = next(iter(doc.related_that("became_rfc")), None) - if became_rfc: - draft_that_became_rfc = became_rfc + draft_that_became_rfc = doc.came_from_draft() + # submission submission = "" if group is None: @@ -651,6 +647,7 @@ def document_main(request, name, rev=None, document_html=False): 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() + debug.show("doc.name") return render(request, "doc/document_draft.html" if document_html is False else "doc/document_html.html", dict(doc=doc, @@ -1134,6 +1131,9 @@ def document_email(request,name): def get_diff_revisions(request, name, doc): + """ returns list of (name, rev, time, url, is_this_doc, is_previous_doc) + ordered by -time for use by forms used to get to the diff tools. + """ diffable = any( [ name.startswith(prefix) @@ -1160,16 +1160,17 @@ def get_diff_revisions(request, name, doc): relateddocument__relationship="replaces", ) ) - diff_documents.extend( - Document.objects.filter( - relateddocument__target=doc, - relateddocument__relationship="became_rfc" - ) - ) + if doc.came_from_draft(): + diff_documents.append(doc.came_from_draft()) + + if doc.became_rfc(): + rfc = doc.became_rfc() + e = rfc.latest_event(type="published_rfc") + diff_revisions.append((rfc.name, "", e.time if e else rfc.time, rfc.name, False, False)) if doc.type_id == "rfc": e = doc.latest_event(type="published_rfc") - diff_revisions.append((name, "", e.time if e else doc.time, name)) + diff_revisions.append((name, "", e.time if e else doc.time, name, True, False)) seen = set() for e in ( @@ -1198,7 +1199,16 @@ def get_diff_revisions(request, name, doc): # rfcdiff tool has special support for IDs url = e.doc.name + "-" + e.rev - diff_revisions.append((e.doc.name, e.rev, e.time, url)) + diff_revisions.append((e.doc.name, e.rev, e.time, url, e.doc == doc and e.rev == doc.rev, False)) + + diff_revisions.sort(key=lambda t: t[2], reverse=True) + for index, t in enumerate(diff_revisions): + if t[4]: # is_this_doc + n = index+1 + if n < len(diff_revisions): + t_name, rev, time, url, _, _ = diff_revisions[n] + diff_revisions[n] = (t_name, rev, time, url, False, True) + break return diff_revisions @@ -1280,7 +1290,7 @@ def document_bibtex(request, name, rev=None): if doc.type_id == "draft": latest_revision = doc.latest_event(NewRevisionDocEvent, type="new_revision") replaced_by = [d.name for d in doc.related_that("replaces")] - draft_became_rfc = next(iter(doc.related_that_doc("became_rfc")), None) + draft_became_rfc = doc.became_rfc() if rev != None and rev != doc.rev: # find the entry in the history @@ -2170,7 +2180,7 @@ def idnits2_state(request, name, rev=None): raise Http404 zero_revision = None if doc.type_id == "rfc": - draft = next(iter(doc.related_that('became_rfc')), None) + draft = doc.came_from_draft() if draft: zero_revision = NewRevisionDocEvent.objects.filter(doc=draft,rev='00').first() else: diff --git a/ietf/idindex/index.py b/ietf/idindex/index.py index b413f3dbd..11c452148 100644 --- a/ietf/idindex/index.py +++ b/ietf/idindex/index.py @@ -33,7 +33,7 @@ def all_id_txt(): rfcs = dict() for rfc in Document.objects.filter(type_id="rfc"): - draft = next(iter(rfc.related_that("became_rfc")), None) + draft = rfc.came_from_draft() if draft is not None: rfcs[draft.name] = rfc.name @@ -117,7 +117,7 @@ def all_id2_txt(): rfcs = dict() for rfc in Document.objects.filter(type_id="rfc"): - draft = next(iter(rfc.related_that("became_rfc")), None) + draft = rfc.came_from_draft() if draft is not None: rfcs[draft.name] = rfc.name diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index 4c30c67f8..edf7b0ab9 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -235,7 +235,7 @@ def _get_materials_doc(meeting, name): docname, rev = name.rsplit("-", 1) if len(rev) == 2 and rev.isdigit(): doc = Document.objects.get(name=docname) # may raise Document.DoesNotExist - if doc.get_related_meeting() == meeting and rev in doc.revisions(): + if doc.get_related_meeting() == meeting and rev in doc.revisions_by_newrevisionevent(): return doc, rev # give up raise Document.DoesNotExist diff --git a/ietf/templates/doc/document_history_form.html b/ietf/templates/doc/document_history_form.html index 30e0d2800..ece0f722a 100644 --- a/ietf/templates/doc/document_history_form.html +++ b/ietf/templates/doc/document_history_form.html @@ -11,7 +11,6 @@
{% endif %} -{% with prev_rev=doc.rev|add:"-1"|stringformat:"02d" %}