chore: merge feat/rfc
This commit is contained in:
commit
ad0071fd7d
1
.github/workflows/ci-run-tests.yml
vendored
1
.github/workflows/ci-run-tests.yml
vendored
|
@ -4,7 +4,6 @@ on:
|
|||
pull_request:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'feat/rfc'
|
||||
paths:
|
||||
- 'client/**'
|
||||
- 'ietf/**'
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -113,6 +113,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'
|
||||
|
@ -131,28 +154,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'
|
||||
|
@ -171,30 +177,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):
|
||||
|
||||
|
@ -217,34 +205,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):
|
||||
|
||||
|
@ -545,30 +510,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
|
||||
|
|
|
@ -175,7 +175,7 @@ class AddDownrefForm(forms.Form):
|
|||
drafts = self.cleaned_data['drafts']
|
||||
for d in drafts:
|
||||
if RelatedDocument.objects.filter(source=d, target=rfc, relationship_id='downref-approval'):
|
||||
v_err_pairs.append(d.name + " --> RFC " + rfc.rfc_number())
|
||||
v_err_pairs.append(f"{d.name} --> RFC {rfc.rfc_number}")
|
||||
if v_err_pairs:
|
||||
raise forms.ValidationError("Downref is already in the registry: " + ", ".join(v_err_pairs))
|
||||
|
||||
|
@ -189,7 +189,8 @@ class AddDownrefForm(forms.Form):
|
|||
else:
|
||||
v_err_refnorm = d.name
|
||||
if v_err_refnorm:
|
||||
v_err_refnorm_prefix = "There does not seem to be a normative reference to RFC " + rfc.rfc_number() + " by "
|
||||
v_err_refnorm_prefix = f"There does not seem to be a normative reference to RFC {rfc.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)
|
||||
|
||||
|
||||
|
|
23
ietf/doc/migrations/0005_add_rfc_states.py
Normal file
23
ietf/doc/migrations/0005_add_rfc_states.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# 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")
|
||||
State.objects.get_or_create(
|
||||
type=rfc_statetype, slug="published", name="Published", used=True, order=1
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("doc", "0004_alter_dochistory_ad_alter_dochistory_shepherd_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward),
|
||||
]
|
|
@ -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),
|
||||
),
|
||||
]
|
75
ietf/doc/migrations/0007_create_rfc_documents.py
Normal file
75
ietf/doc/migrations/0007_create_rfc_documents.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
# 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])
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("doc", "0006_dochistory_rfc_number_document_rfc_number"),
|
||||
("name", "0004_rfc_doctype_names"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward),
|
||||
]
|
98
ietf/doc/migrations/0008_move_rfc_docevents.py
Normal file
98
ietf/doc/migrations/0008_move_rfc_docevents.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
# Generated by Django 4.2.2 on 2023-06-20 18:36
|
||||
|
||||
from django.db import migrations
|
||||
from django.db.models import Q
|
||||
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
"""Move RFC events from the draft to the rfc Document"""
|
||||
DocAlias = apps.get_model("doc", "DocAlias")
|
||||
DocEvent = apps.get_model("doc", "DocEvent")
|
||||
Document = apps.get_model("doc", "Document")
|
||||
|
||||
# queryset with events migrated regardless of whether before or after the "published_rfc" event
|
||||
events_always_migrated = DocEvent.objects.filter(
|
||||
Q(
|
||||
type__in=[
|
||||
"published_rfc", # do not remove this one!
|
||||
"sync_from_rfc_editor",
|
||||
"rfc_editor_received_announcement", # problematic for new RFCs until RPC tools enhancements come in?
|
||||
]
|
||||
)
|
||||
| Q(
|
||||
type="changed_state",
|
||||
desc__startswith="RFC Editor state",
|
||||
)
|
||||
| Q(
|
||||
type="changed_state",
|
||||
desc__startswith="IANA Action state",
|
||||
)
|
||||
)
|
||||
|
||||
# queryset with events migrated only after the "published_rfc" event
|
||||
events_migrated_after_pub = DocEvent.objects.exclude(
|
||||
type__in=[
|
||||
"created_ballot",
|
||||
"closed_ballot",
|
||||
"sent_ballot_announcement",
|
||||
"changed_ballot_position",
|
||||
"changed_ballot_approval_text",
|
||||
"changed_ballot_writeup_text",
|
||||
]
|
||||
).exclude(
|
||||
type="added_comment",
|
||||
desc__contains="ballot set", # excludes 311 comments that all apply to drafts
|
||||
)
|
||||
|
||||
# special case for rfc 6312/6342 draft, which has two published_rfc events
|
||||
ignore = ["rfc6312", "rfc6342"] # do not reprocess these later
|
||||
rfc6312 = Document.objects.get(name="rfc6312")
|
||||
rfc6342 = Document.objects.get(name="rfc6342")
|
||||
draft = DocAlias.objects.get(name="rfc6312").docs.first()
|
||||
assert draft == DocAlias.objects.get(name="rfc6342").docs.first()
|
||||
published_events = list(
|
||||
DocEvent.objects.filter(doc=draft, type="published_rfc").order_by("time")
|
||||
)
|
||||
assert len(published_events) == 2
|
||||
(
|
||||
pub_event_6312,
|
||||
pub_event_6342,
|
||||
) = published_events # order matches pub dates at rfc-editor.org
|
||||
|
||||
pub_event_6312.doc = rfc6312
|
||||
pub_event_6312.save()
|
||||
events_migrated_after_pub.filter(
|
||||
doc=draft,
|
||||
time__gte=pub_event_6312.time,
|
||||
time__lt=pub_event_6342.time,
|
||||
).update(doc=rfc6312)
|
||||
|
||||
pub_event_6342.doc = rfc6342
|
||||
pub_event_6342.save()
|
||||
events_migrated_after_pub.filter(
|
||||
doc=draft,
|
||||
time__gte=pub_event_6342.time,
|
||||
).update(doc=rfc6342)
|
||||
|
||||
# Now handle all the rest
|
||||
for rfc in Document.objects.filter(type_id="rfc").exclude(name__in=ignore):
|
||||
draft = DocAlias.objects.get(name=rfc.name).docs.first()
|
||||
assert draft is not None
|
||||
published_event = DocEvent.objects.get(doc=draft, type="published_rfc")
|
||||
events_always_migrated.filter(
|
||||
doc=draft,
|
||||
).update(doc=rfc)
|
||||
events_migrated_after_pub.filter(
|
||||
doc=draft,
|
||||
time__gte=published_event.time,
|
||||
).update(doc=rfc)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("doc", "0007_create_rfc_documents"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward),
|
||||
]
|
22
ietf/doc/migrations/0009_move_rfc_docaliases.py
Normal file
22
ietf/doc/migrations/0009_move_rfc_docaliases.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 4.2.2 on 2023-06-20 18:36
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
"""Point "rfc..." DocAliases at the rfc-type Document"""
|
||||
DocAlias = apps.get_model("doc", "DocAlias")
|
||||
Document = apps.get_model("doc", "Document")
|
||||
for rfc_alias in DocAlias.objects.filter(name__startswith="rfc"):
|
||||
rfc = Document.objects.get(name=rfc_alias.name)
|
||||
rfc_alias.docs.set([rfc])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("doc", "0008_move_rfc_docevents"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward),
|
||||
]
|
|
@ -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 = []
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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.rfc_number())].append(int(r.source.rfc_number()))
|
||||
obsdict[int(r.target.rfc_number)].append(int(r.source.rfc_number)) # Aren't these already guaranteed to be ints?
|
||||
for k in obsdict:
|
||||
obsdict[k] = sorted(obsdict[k])
|
||||
return render_to_string('doc/idnits2-rfcs-obsoleted.txt', context={'obsitems':sorted(obsdict.items())})
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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.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,
|
||||
rev=rel.target.rev, by=login)
|
||||
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
|
||||
rel.target.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())
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -44,12 +44,14 @@ def downref_registry_add(request):
|
|||
c = DocEvent(type="downref_approved", doc=d,
|
||||
rev=d.rev, by=login)
|
||||
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
|
||||
rfc.rfc_number(), d.name, d.rev)
|
||||
rfc.rfc_number, d.name, d.rev)
|
||||
rfc.document.rfc_number, da.name, da.document.rev)
|
||||
c.save()
|
||||
c = DocEvent(type="downref_approved", doc=rfc,
|
||||
rev=rfc.rev, by=login)
|
||||
c.desc = "Downref to RFC %s approved by Last Call for %s-%s" % (
|
||||
rfc.rfc_number(), d.name, d.rev)
|
||||
rfc.rfc_number, d.name, d.rev)
|
||||
rfc.document.rfc_number, da.name, da.document.rev)
|
||||
c.save()
|
||||
|
||||
return HttpResponseRedirect(urlreverse('ietf.doc.views_downref.downref_registry'))
|
||||
|
|
|
@ -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'):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"):
|
||||
|
|
|
@ -2539,6 +2539,19 @@
|
|||
"model": "doc.state",
|
||||
"pk": 174
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"name": "Published",
|
||||
"next_states": [],
|
||||
"order": 1,
|
||||
"slug": "published",
|
||||
"type": "rfc",
|
||||
"used": true
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 175
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"label": "State"
|
||||
|
@ -2721,6 +2734,13 @@
|
|||
"model": "doc.statetype",
|
||||
"pk": "review"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"label": "State"
|
||||
},
|
||||
"model": "doc.statetype",
|
||||
"pk": "rfc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"label": "Shepherd's Writeup State"
|
||||
|
@ -9890,6 +9910,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 +10591,17 @@
|
|||
"model": "name.doctypename",
|
||||
"pk": "review"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
"name": "RFC",
|
||||
"order": 0,
|
||||
"prefix": "rfc",
|
||||
"used": true
|
||||
},
|
||||
"model": "name.doctypename",
|
||||
"pk": "rfc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "",
|
||||
|
|
30
ietf/name/migrations/0004_rfc_doctype_names.py
Normal file
30
ietf/name/migrations/0004_rfc_doctype_names.py
Normal 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),
|
||||
]
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 %}
|
||||
|
|
Loading…
Reference in a new issue