refactor: Represent RFCs as their own DocType (#5835)

* feat: Add RFC DocTypeName, StateType, and States

* refactor: Rename rfc_number() to deprecated_rfc_number()

* feat: Add rfc_number field to DocInfo

* feat: Add DocRelationshipName "became-rfc"

* chore: First-pass migration to create rfc Documents

* chore: create_rfc_documents migration depends on new names

* refactor: Rename variable

* fix: Fix revname / downcase name for "became-rfc" DocRelationshipName

* chore: Remove debugging print statements

* feat: Point rfc aliases at rfc Documents

* test: Refactor RFC factories

* refactor: Rewrite is_rfc() in terms of type_id

* test: Use RfcFactory as base for IndividualRfcFactory

* refactor: Replace calls to deprecated_rfc_number()

* refactor: Remove deprecated_rfc_number() method

* test: Import WgRfcFactory
This commit is contained in:
Jennifer Richards 2023-06-20 15:28:16 -03:00 committed by GitHub
parent 7798ea8d66
commit f2c2957925
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 301 additions and 159 deletions

View file

@ -24,7 +24,7 @@ import debug # pyflakes:ignore
import ietf
from ietf.doc.utils import get_unicode_document_content
from ietf.doc.models import RelatedDocument, State
from ietf.doc.factories import IndividualDraftFactory, WgDraftFactory
from ietf.doc.factories import IndividualDraftFactory, WgDraftFactory, WgRfcFactory
from ietf.group.factories import RoleFactory
from ietf.meeting.factories import MeetingFactory, SessionFactory
from ietf.meeting.models import Session
@ -968,9 +968,9 @@ class RfcdiffSupportTests(TestCase):
draft.set_state(State.objects.get(type_id='draft',slug='rfc'))
draft.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
draft = reload_db_objects(draft)
rfc = draft
rfc = WgRfcFactory(group=draft.group) # todo link this with its pre-publication draft
number = rfc.rfc_number()
number = rfc.rfc_number
received = self.getJson(dict(name=number))
self.assertEqual(
received,

View file

@ -340,10 +340,7 @@ def rfcdiff_latest_json(request, name, rev=None):
response['name']=doc.canonical_name()
if doc.name != doc.canonical_name():
prev_rev = doc.rev
# not sure what to do if non-numeric values come back, so at least log it
log.assertion('doc.rfc_number().isdigit()') # .rfc_number() is expensive...
log.assertion('doc.rev.isdigit()')
if int(doc.rfc_number()) in HAS_TOMBSTONE and prev_rev != '00':
if doc.rfc_number in HAS_TOMBSTONE and prev_rev != '00':
prev_rev = f'{(int(doc.rev)-1):02d}'
response['previous'] = f'{doc.name}-{prev_rev}'
response['previous_url'] = get_previous_url(doc.name, prev_rev)

View file

@ -84,7 +84,7 @@ for changes, doc, rfc_published in ietf.sync.rfceditor.update_docs_from_rfc_inde
new_rfcs.append(doc)
for c in changes:
log("RFC%s, %s: %s" % (doc.rfcnum, doc.name, c))
log("RFC%s, %s: %s" % (doc.rfc_number, doc.name, c))
sys.exit(0)

View file

@ -119,6 +119,29 @@ class DocumentFactory(BaseDocumentFactory):
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
class RfcFactory(BaseDocumentFactory):
type_id = "rfc"
rfc_number = factory.Sequence(lambda n: n + 1000)
name = factory.LazyAttribute(lambda o: f"rfc{o.rfc_number:04d}")
expires = None
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
else:
obj.set_state(State.objects.get(type_id='rfc',slug='published'))
@factory.post_generation
def reset_canonical_name(obj, create, extracted, **kwargs):
if hasattr(obj, '_canonical_name'):
del obj._canonical_name
return None
class IndividualDraftFactory(BaseDocumentFactory):
type_id = 'draft'
@ -137,28 +160,11 @@ class IndividualDraftFactory(BaseDocumentFactory):
obj.set_state(State.objects.get(type_id='draft',slug='active'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class IndividualRfcFactory(IndividualDraftFactory):
class IndividualRfcFactory(RfcFactory):
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
else:
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
@factory.post_generation
def reset_canonical_name(obj, create, extracted, **kwargs):
if hasattr(obj, '_canonical_name'):
del obj._canonical_name
return None
class WgDraftFactory(BaseDocumentFactory):
type_id = 'draft'
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='wg')
stream_id = 'ietf'
@ -177,30 +183,12 @@ class WgDraftFactory(BaseDocumentFactory):
obj.set_state(State.objects.get(type_id='draft-stream-ietf',slug='wg-doc'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class WgRfcFactory(WgDraftFactory):
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
class WgRfcFactory(RfcFactory):
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='wg')
stream_id = 'ietf'
std_level_id = 'ps'
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
obj.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
@factory.post_generation
def reset_canonical_name(obj, create, extracted, **kwargs):
if hasattr(obj, '_canonical_name'):
del obj._canonical_name
return None
class RgDraftFactory(BaseDocumentFactory):
@ -223,34 +211,11 @@ class RgDraftFactory(BaseDocumentFactory):
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class RgRfcFactory(RgDraftFactory):
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
class RgRfcFactory(RfcFactory):
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='rg')
stream_id = 'irtf'
std_level_id = 'inf'
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-stream-irtf'):
obj.set_state(State.objects.get(type_id='draft-stream-irtf', slug='pub'))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
obj.set_state(State.objects.get(type_id='draft-stream-irtf', slug='pub'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
@factory.post_generation
def reset_canonical_name(obj, create, extracted, **kwargs):
if hasattr(obj, '_canonical_name'):
del obj._canonical_name
return None
class CharterFactory(BaseDocumentFactory):
@ -551,30 +516,5 @@ class EditorialDraftFactory(BaseDocumentFactory):
obj.set_state(State.objects.get(type_id='draft-stream-editorial',slug='active'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class EditorialRfcFactory(RgDraftFactory):
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
std_level_id = 'inf'
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-stream-editorial'):
obj.set_state(State.objects.get(type_id='draft-stream-editorial', slug='pub'))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
obj.set_state(State.objects.get(type_id='draft-stream-editorial', slug='pub'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
@factory.post_generation
def reset_canonical_name(obj, create, extracted, **kwargs):
if hasattr(obj, '_canonical_name'):
del obj._canonical_name
return None
class EditorialRfcFactory(RgRfcFactory):
pass

View file

@ -175,7 +175,7 @@ class AddDownrefForm(forms.Form):
drafts = self.cleaned_data['drafts']
for da in drafts:
if RelatedDocument.objects.filter(source=da.document, target=rfc, relationship_id='downref-approval'):
v_err_pairs.append(da.name + " --> RFC " + rfc.document.rfc_number())
v_err_pairs.append(f"{da.name} --> RFC {rfc.document.rfc_number}")
if v_err_pairs:
raise forms.ValidationError("Downref is already in the registry: " + ", ".join(v_err_pairs))
@ -189,7 +189,7 @@ class AddDownrefForm(forms.Form):
else:
v_err_refnorm = da.name
if v_err_refnorm:
v_err_refnorm_prefix = "There does not seem to be a normative reference to RFC " + rfc.document.rfc_number() + " by "
v_err_refnorm_prefix = f"There does not seem to be a normative reference to RFC {rfc.document.rfc_number} by "
raise forms.ValidationError(v_err_refnorm_prefix + v_err_refnorm)

View file

@ -0,0 +1,27 @@
# Generated by Django 4.2.2 on 2023-06-14 20:57
from django.db import migrations
def forward(apps, schema_editor):
StateType = apps.get_model("doc", "StateType")
rfc_statetype, _ = StateType.objects.get_or_create(slug="rfc", label="State")
State = apps.get_model("doc", "State")
created_state, _ = State.objects.get_or_create(
type=rfc_statetype, slug="created", name="Created", used=True, order=1
)
published_state, _ = State.objects.get_or_create(
type=rfc_statetype, slug="published", name="Published", used=True, order=2
)
created_state.next_states.add(published_state)
class Migration(migrations.Migration):
dependencies = [
("doc", "0004_alter_dochistory_ad_alter_dochistory_shepherd_and_more"),
]
operations = [
migrations.RunPython(forward),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 4.2.2 on 2023-06-14 22:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("doc", "0005_add_rfc_states"),
]
operations = [
migrations.AddField(
model_name="dochistory",
name="rfc_number",
field=models.PositiveIntegerField(blank=True, null=True),
),
migrations.AddField(
model_name="document",
name="rfc_number",
field=models.PositiveIntegerField(blank=True, null=True),
),
]

View file

@ -0,0 +1,79 @@
# Generated by Django 4.2.2 on 2023-06-15 15:27
from django.db import migrations
def forward(apps, schema_editor):
Document = apps.get_model("doc", "Document")
DocAlias = apps.get_model("doc", "DocAlias")
DocumentAuthor = apps.get_model("doc", "DocumentAuthor")
State = apps.get_model("doc", "State")
draft_rfc_state = State.objects.get(type_id="draft", slug="rfc")
rfc_published_state = State.objects.get(type_id="rfc", slug="published")
DocTypeName = apps.get_model("name", "DocTypeName")
rfc_doctype = DocTypeName(slug="rfc")
# Find draft Documents in the "rfc" state
found_by_state = Document.objects.filter(states=draft_rfc_state).distinct()
# Find Documents with an "rfc..." alias and confirm they're the same set
rfc_docaliases = DocAlias.objects.filter(name__startswith="rfc")
found_by_name = Document.objects.filter(docalias__in=rfc_docaliases).distinct()
assert set(found_by_name) == set(found_by_state), "mismatch between rfcs identified by state and docalias"
# As of 2023-06-15, there is one Document with two rfc aliases: rfc6312 and rfc6342 are the same Document. This
# was due to a publication error. We'll handle that specially.
for rfc_alias in rfc_docaliases.order_by("name"):
assert rfc_alias.docs.count() == 1, f"DocAlias {rfc_alias} is linked to more than 1 Document"
draft = rfc_alias.docs.first()
if draft.name.startswith("rfc"):
rfc = draft
rfc.type = rfc_doctype
rfc.rfc_number = int(draft.name[3:])
rfc.save()
rfc.states.set([rfc_published_state])
# Alias already points at the rfc document
else:
rfc = Document.objects.create(
type=rfc_doctype,
name=rfc_alias.name,
rfc_number=int(rfc_alias.name[3:]),
title=draft.title,
abstract=draft.abstract,
pages=draft.pages,
words=draft.words,
std_level=draft.std_level,
external_url=draft.external_url,
uploaded_filename=draft.uploaded_filename,
note=draft.note,
)
rfc.states.set([rfc_published_state])
rfc.formal_languages.set(draft.formal_languages.all())
# Copy Authors
for da in draft.documentauthor_set.all():
DocumentAuthor.objects.create(
document=rfc,
person=da.person,
email=da.email,
affiliation=da.affiliation,
country=da.country,
order=da.order,
)
# Point alias at the new rfc Document
rfc_alias.docs.set([rfc])
class Migration(migrations.Migration):
dependencies = [
("doc", "0006_dochistory_rfc_number_document_rfc_number"),
("name", "0004_rfc_doctype_names"),
]
operations = [
migrations.RunPython(forward),
]

View file

@ -124,6 +124,7 @@ class DocumentInfo(models.Model):
uploaded_filename = models.TextField(blank=True)
note = models.TextField(blank=True)
internal_comments = models.TextField(blank=True)
rfc_number = models.PositiveIntegerField(blank=True, null=True) # only valid for type="rfc"
def file_extension(self):
if not hasattr(self, '_cached_extension'):
@ -334,7 +335,9 @@ class DocumentInfo(models.Model):
if not state:
return "Unknown state"
if self.type_id == 'draft':
if self.type_id == "rfc":
return f"RFC {self.rfc_number} ({self.std_level})"
elif self.type_id == 'draft':
iesg_state = self.get_state("draft-iesg")
iesg_state_summary = None
if iesg_state:
@ -345,7 +348,13 @@ class DocumentInfo(models.Model):
iesg_state_summary = iesg_state_summary + "::"+"::".join(tag.name for tag in iesg_substate)
if state.slug == "rfc":
return "RFC %s (%s)" % (self.rfc_number(), self.std_level)
# todo check this once became-rfc relationships are actually created
rfcs = self.related_that("became-rfc") # should be only one
if len(rfcs) > 0:
rfc = rfcs[0]
return f"Became RFC {rfc.rfc_number} ({rfc.std_level})"
else:
return "Became RFC"
elif state.slug == "repl":
rs = self.related_that("replaces")
if rs:
@ -376,25 +385,7 @@ class DocumentInfo(models.Model):
return state.name
def is_rfc(self):
if not hasattr(self, '_cached_is_rfc'):
self._cached_is_rfc = self.pk and self.type_id == 'draft' and self.states.filter(type='draft',slug='rfc').exists()
return self._cached_is_rfc
def rfc_number(self):
if not hasattr(self, '_cached_rfc_number'):
self._cached_rfc_number = None
if self.is_rfc():
n = self.canonical_name()
if n.startswith("rfc"):
self._cached_rfc_number = n[3:]
else:
if isinstance(self,Document):
logger.error("Document self.is_rfc() is True but self.canonical_name() is %s" % n)
return self._cached_rfc_number
@property
def rfcnum(self):
return self.rfc_number()
return self.type_id == "rfc"
def author_list(self):
best_addresses = []

View file

@ -792,12 +792,12 @@ Man Expires September 22, 2015 [Page 3]
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.canonical_name())))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(q('title').text(), f'RFC {rfc.rfc_number()} - {rfc.title}')
self.assertEqual(q('title').text(), f'RFC {rfc.rfc_number} - {rfc.title}')
# synonyms for the rfc should be redirected to its canonical view
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.rfc_number())))
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.rfc_number)))
self.assertRedirects(r, urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.canonical_name())))
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=f'RFC {rfc.rfc_number()}')))
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=f'RFC {rfc.rfc_number}')))
self.assertRedirects(r, urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.canonical_name())))
# expired draft
@ -1954,7 +1954,7 @@ class DocTestCase(TestCase):
std_level_id = 'ps',
time = datetime.datetime(2010, 10, 10, tzinfo=ZoneInfo(settings.TIME_ZONE)),
)
num = rfc.rfc_number()
num = rfc.rfc_number
DocEventFactory.create(
doc=rfc,
type='published_rfc',

View file

@ -1003,7 +1003,7 @@ def build_file_urls(doc: Union[Document, DocHistory]):
if doc.type_id != 'draft':
return [], []
if doc.get_state_slug() == "rfc":
if doc.is_rfc():
name = doc.canonical_name()
base_path = os.path.join(settings.RFC_PATH, name + ".")
possible_types = settings.RFC_FILE_TYPES
@ -1022,7 +1022,7 @@ def build_file_urls(doc: Union[Document, DocHistory]):
if "txt" in found_types:
file_urls.append(("htmlized", urlreverse('ietf.doc.views_doc.document_html', kwargs=dict(name=name))))
if doc.tags.filter(slug="verified-errata").exists():
file_urls.append(("with errata", settings.RFC_EDITOR_INLINE_ERRATA_URL.format(rfc_number=doc.rfc_number())))
file_urls.append(("with errata", settings.RFC_EDITOR_INLINE_ERRATA_URL.format(rfc_number=doc.rfc_number)))
file_urls.append(("bibtex", urlreverse('ietf.doc.views_doc.document_bibtex',kwargs=dict(name=name))))
elif doc.rev:
base_path = os.path.join(settings.INTERNET_ALL_DRAFTS_ARCHIVE_DIR, doc.name + "-" + doc.rev + ".")
@ -1111,16 +1111,16 @@ def generate_idnits2_rfc_status():
'unkn': 'U',
}
rfcs = Document.objects.filter(type_id='draft',states__slug='rfc',states__type='draft')
rfcs = Document.objects.filter(type_id='rfc',states__slug='published',states__type='rfc')
for rfc in rfcs:
offset = int(rfc.rfcnum)-1
offset = int(rfc.rfc_number)-1
blob[offset] = symbols[rfc.std_level_id]
if rfc.related_that('obs'):
blob[offset] = 'O'
# Workarounds for unusual states in the datatracker
# Document.get(docalias='rfc6312').rfcnum == 6342
# Document.get(docalias='rfc6312').rfc_number == 6342
# 6312 was published with the wrong rfc number in it
# weird workaround in the datatracker - there are two
# DocAliases starting with rfc - the canonical name code
@ -1141,7 +1141,7 @@ def generate_idnits2_rfc_status():
def generate_idnits2_rfcs_obsoleted():
obsdict = defaultdict(list)
for r in RelatedDocument.objects.filter(relationship_id='obs'):
obsdict[int(r.target.document.rfc_number())].append(int(r.source.rfc_number()))
obsdict[int(r.target.document.rfc_number)].append(int(r.source.rfc_number))
for k in obsdict:
obsdict[k] = sorted(obsdict[k])
return render_to_string('doc/idnits2-rfcs-obsoleted.txt', context={'obsitems':sorted(obsdict.items())})

View file

@ -93,7 +93,7 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
# emulate canonical name which is used by a lot of the utils
# d.canonical_name = wrap_value(rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name)
if d.rfc_number() != None and d.latest_event_cache["published_rfc"]:
if d.is_rfc() and d.latest_event_cache["published_rfc"]:
d.latest_revision_date = d.latest_event_cache["published_rfc"].time
elif d.latest_event_cache["new_revision"]:
d.latest_revision_date = d.latest_event_cache["new_revision"].time
@ -198,7 +198,7 @@ def prepare_document_table(request, docs, query=None, max_results=200):
res = []
rfc_num = d.rfc_number()
rfc_num = num(d.rfc_number) if d.rfc_number else None
if d.type_id == "draft":
res.append(num(["Active", "Expired", "Replaced", "Withdrawn", "RFC"].index(d.search_heading.split()[0])))
@ -213,23 +213,23 @@ def prepare_document_table(request, docs, query=None, max_results=200):
elif sort_key == "date":
res.append(str(d.latest_revision_date.astimezone(ZoneInfo(settings.TIME_ZONE))))
elif sort_key == "status":
if rfc_num != None:
res.append(num(rfc_num))
if rfc_num is not None:
res.append(rfc_num)
else:
res.append(num(d.get_state().order) if d.get_state() else None)
elif sort_key == "ipr":
res.append(len(d.ipr()))
elif sort_key == "ad":
if rfc_num != None:
res.append(num(rfc_num))
if rfc_num is not None:
res.append(rfc_num)
elif d.get_state_slug() == "active":
if d.get_state("draft-iesg"):
res.append(d.get_state("draft-iesg").order)
else:
res.append(0)
else:
if rfc_num != None:
res.append(num(rfc_num))
if rfc_num is not None:
res.append(rfc_num)
else:
res.append(d.canonical_name())

View file

@ -968,12 +968,12 @@ def approve_downrefs(request, name):
c = DocEvent(type="downref_approved", doc=rel.source,
rev=rel.source.rev, by=login)
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
rel.target.document.rfc_number(), rel.source, rel.source.rev)
rel.target.document.rfc_number, rel.source, rel.source.rev)
c.save()
c = DocEvent(type="downref_approved", doc=rel.target.document,
rev=rel.target.document.rev, by=login)
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
rel.target.document.rfc_number(), rel.source, rel.source.rev)
rel.target.document.rfc_number, rel.source, rel.source.rev)
c.save()
return HttpResponseRedirect(doc.get_absolute_url())

View file

@ -1074,7 +1074,7 @@ def document_bibtex(request, name, rev=None):
# This needs to be replaced with a lookup, as the mapping may change
# over time. Probably by updating ietf/sync/rfceditor.py to add the
# as a DocAlias, and use a method on Document to retrieve it.
doi = "10.17487/RFC%04d" % int(doc.rfc_number())
doi = f"10.17487/RFC{doc.rfc_number:04d}"
else:
doi = None

View file

@ -44,12 +44,12 @@ def downref_registry_add(request):
c = DocEvent(type="downref_approved", doc=da.document,
rev=da.document.rev, by=login)
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
rfc.document.rfc_number(), da.name, da.document.rev)
rfc.document.rfc_number, da.name, da.document.rev)
c.save()
c = DocEvent(type="downref_approved", doc=rfc.document,
rev=rfc.document.rev, by=login)
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
rfc.document.rfc_number(), da.name, da.document.rev)
rfc.document.rfc_number, da.name, da.document.rev)
c.save()
return HttpResponseRedirect(urlreverse('ietf.doc.views_downref.downref_registry'))

View file

@ -409,8 +409,8 @@ def shorten_group_name(name):
def ad_dashboard_sort_key(doc):
if doc.type.slug=='draft' and doc.get_state_slug('draft') == 'rfc':
return "21%04d" % int(doc.rfc_number())
if doc.type.slug=='rfc' and doc.get_state_slug('rfc') == 'published':
return "21%04d" % int(doc.rfc_number)
if doc.type.slug=='statchg' and doc.get_state_slug('statchg') == 'appr-sent':
return "22%d" % 0 # TODO - get the date of the transition into this state here
if doc.type.slug=='conflrev' and doc.get_state_slug('conflrev') in ('appr-reqnopub-sent','appr-noprob-sent'):

View file

@ -534,9 +534,8 @@ def group_documents_txt(request, acronym, group_type=None):
rows = []
for d in itertools.chain(docs, docs_related):
rfc_number = d.rfc_number()
if rfc_number != None:
name = rfc_number
if d.is_rfc():
name = str(d.rfc_number)
else:
name = "%s-%s" % (d.name, d.rev)

View file

@ -151,8 +151,8 @@ def agenda_json(request, date=None):
if doc.type_id == "draft":
docinfo['rev'] = doc.rev
docinfo['intended-std-level'] = str(doc.intended_std_level)
if doc.rfc_number():
docinfo['rfc-number'] = doc.rfc_number()
if doc.is_rfc():
docinfo['rfc-number'] = doc.rfc_number
iana_state = doc.get_state("draft-iana-review")
if iana_state and iana_state.slug in ("not-ok", "changed", "need-rev"):

View file

@ -2539,6 +2539,34 @@
"model": "doc.state",
"pk": 174
},
{
"fields": {
"desc": "",
"name": "Created",
"next_states": [
176
],
"order": 1,
"slug": "created",
"type": "rfc",
"used": true
},
"model": "doc.state",
"pk": 175
},
{
"fields": {
"desc": "",
"name": "Published",
"next_states": [],
"order": 2,
"slug": "published",
"type": "rfc",
"used": true
},
"model": "doc.state",
"pk": 176
},
{
"fields": {
"label": "State"
@ -2721,6 +2749,13 @@
"model": "doc.statetype",
"pk": "review"
},
{
"fields": {
"label": "State"
},
"model": "doc.statetype",
"pk": "rfc"
},
{
"fields": {
"label": "Shepherd's Writeup State"
@ -9890,6 +9925,17 @@
"model": "name.dbtemplatetypename",
"pk": "rst"
},
{
"fields": {
"desc": "",
"name": "Became RFC",
"order": 0,
"revname": "Became RFC as",
"used": true
},
"model": "name.docrelationshipname",
"pk": "became-rfc"
},
{
"fields": {
"desc": "",
@ -10560,6 +10606,17 @@
"model": "name.doctypename",
"pk": "review"
},
{
"fields": {
"desc": "",
"name": "RFC",
"order": 0,
"prefix": "rfc",
"used": true
},
"model": "name.doctypename",
"pk": "rfc"
},
{
"fields": {
"desc": "",

View file

@ -0,0 +1,30 @@
# Generated by Django 4.2.2 on 2023-06-14 20:39
from django.db import migrations
def forward(apps, schema_editor):
DocTypeName = apps.get_model("name", "DocTypeName")
DocTypeName.objects.get_or_create(
slug="rfc",
name="RFC",
used=True,
prefix="rfc",
)
DocRelationshipName = apps.get_model("name", "DocRelationshipName")
DocRelationshipName.objects.get_or_create(
slug="became-rfc",
name="became RFC",
used=True,
revname="came from draft",
)
class Migration(migrations.Migration):
dependencies = [
("name", "0003_populate_telechatagendasectionname"),
]
operations = [
migrations.RunPython(forward),
]

View file

@ -42,7 +42,7 @@ class DocRelationshipName(NameModel):
class DocTypeName(NameModel):
"""Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email,
Review, Issue, Wiki"""
Review, Issue, Wiki, RFC"""
prefix = models.CharField(max_length=16, default="")
class DocTagName(NameModel):
"""Waiting for Reference, IANA Coordination, Revised ID Needed,

View file

@ -705,7 +705,7 @@ LIAISON_ATTACH_URL = 'https://www.ietf.org/lib/dt/documents/LIAISON/' # should e
DOC_HREFS = {
"charter": "https://www.ietf.org/charter/{doc.name}-{doc.rev}.txt",
"draft": "https://www.ietf.org/archive/id/{doc.name}-{doc.rev}.txt",
"rfc": "https://www.rfc-editor.org/rfc/rfc{doc.rfcnum}.txt",
"rfc": "https://www.rfc-editor.org/rfc/rfc{doc.rfc_number}.txt",
"slides": "https://www.ietf.org/slides/{doc.name}-{doc.rev}",
"procmaterials": "https://www.ietf.org/procmaterials/{doc.name}-{doc.rev}",
"conflrev": "https://www.ietf.org/cr/{doc.name}-{doc.rev}.txt",

View file

@ -1,7 +1,7 @@
{% load ietf_filters %}{% filter linebreaks_lf %}{% comment %}
{% endcomment %}Doc-tag: {{doc.name}};datatracker{% if doc.rfcnum %}
Doc-rfcnum: {{doc.rfcnum}}{% endif %}
{% endcomment %}Doc-tag: {{doc.name}};datatracker{% if doc.is_rfc %}
Doc-rfcnum: {{doc.rfc_number}}{% endif %}
Doc-created: {{doc.created|date:"Y-m-d"}};datatracker{% if doc.deststatus %}
Doc-deststatus: {{doc.deststatus}};datatracker{% endif %}
Doc-rev: {{doc.rev}};datatracker
{% endfilter %}
{% endfilter %}