Skip to content

Commit ad0071f

Browse files
committed
chore: merge feat/rfc
2 parents 69f882d + 106c67e commit ad0071f

26 files changed

Lines changed: 398 additions & 157 deletions

.github/workflows/ci-run-tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ on:
44
pull_request:
55
branches:
66
- 'main'
7-
- 'feat/rfc'
87
paths:
98
- 'client/**'
109
- 'ietf/**'

ietf/api/tests.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import ietf
2525
from ietf.doc.utils import get_unicode_document_content
2626
from ietf.doc.models import RelatedDocument, State
27-
from ietf.doc.factories import IndividualDraftFactory, WgDraftFactory
27+
from ietf.doc.factories import IndividualDraftFactory, WgDraftFactory, WgRfcFactory
2828
from ietf.group.factories import RoleFactory
2929
from ietf.meeting.factories import MeetingFactory, SessionFactory
3030
from ietf.meeting.models import Session
@@ -968,9 +968,9 @@ def do_rfc_test(self, draft_name):
968968
draft.set_state(State.objects.get(type_id='draft',slug='rfc'))
969969
draft.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
970970
draft = reload_db_objects(draft)
971-
rfc = draft
971+
rfc = WgRfcFactory(group=draft.group) # todo link this with its pre-publication draft
972972

973-
number = rfc.rfc_number()
973+
number = rfc.rfc_number
974974
received = self.getJson(dict(name=number))
975975
self.assertEqual(
976976
received,

ietf/api/views.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,7 @@ def rfcdiff_latest_json(request, name, rev=None):
340340
response['name']=doc.canonical_name()
341341
if doc.name != doc.canonical_name():
342342
prev_rev = doc.rev
343-
# not sure what to do if non-numeric values come back, so at least log it
344-
log.assertion('doc.rfc_number().isdigit()') # .rfc_number() is expensive...
345-
log.assertion('doc.rev.isdigit()')
346-
if int(doc.rfc_number()) in HAS_TOMBSTONE and prev_rev != '00':
343+
if doc.rfc_number in HAS_TOMBSTONE and prev_rev != '00':
347344
prev_rev = f'{(int(doc.rev)-1):02d}'
348345
response['previous'] = f'{doc.name}-{prev_rev}'
349346
response['previous_url'] = get_previous_url(doc.name, prev_rev)

ietf/bin/rfc-editor-index-updates

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ for changes, doc, rfc_published in ietf.sync.rfceditor.update_docs_from_rfc_inde
8484
new_rfcs.append(doc)
8585

8686
for c in changes:
87-
log("RFC%s, %s: %s" % (doc.rfcnum, doc.name, c))
87+
log("RFC%s, %s: %s" % (doc.rfc_number, doc.name, c))
8888

8989
sys.exit(0)
9090

ietf/doc/factories.py

Lines changed: 30 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -113,27 +113,11 @@ class DocumentFactory(BaseDocumentFactory):
113113
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
114114

115115

116-
class IndividualDraftFactory(BaseDocumentFactory):
117-
118-
type_id = 'draft'
119-
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
120-
121-
@factory.post_generation
122-
def states(obj, create, extracted, **kwargs):
123-
if not create:
124-
return
125-
if extracted:
126-
for (state_type_id,state_slug) in extracted:
127-
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
128-
if not obj.get_state('draft-iesg'):
129-
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
130-
else:
131-
obj.set_state(State.objects.get(type_id='draft',slug='active'))
132-
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
133-
134-
class IndividualRfcFactory(IndividualDraftFactory):
135-
136-
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
116+
class RfcFactory(BaseDocumentFactory):
117+
type_id = "rfc"
118+
rfc_number = factory.Sequence(lambda n: n + 1000)
119+
name = factory.LazyAttribute(lambda o: f"rfc{o.rfc_number:04d}")
120+
expires = None
137121

138122
@factory.post_generation
139123
def states(obj, create, extracted, **kwargs):
@@ -143,19 +127,19 @@ def states(obj, create, extracted, **kwargs):
143127
for (state_type_id,state_slug) in extracted:
144128
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
145129
else:
146-
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
130+
obj.set_state(State.objects.get(type_id='rfc',slug='published'))
147131

148132
@factory.post_generation
149133
def reset_canonical_name(obj, create, extracted, **kwargs):
150134
if hasattr(obj, '_canonical_name'):
151135
del obj._canonical_name
152136
return None
153137

154-
class WgDraftFactory(BaseDocumentFactory):
138+
139+
class IndividualDraftFactory(BaseDocumentFactory):
155140

156141
type_id = 'draft'
157-
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='wg')
158-
stream_id = 'ietf'
142+
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
159143

160144
@factory.post_generation
161145
def states(obj, create, extracted, **kwargs):
@@ -168,14 +152,16 @@ def states(obj, create, extracted, **kwargs):
168152
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
169153
else:
170154
obj.set_state(State.objects.get(type_id='draft',slug='active'))
171-
obj.set_state(State.objects.get(type_id='draft-stream-ietf',slug='wg-doc'))
172155
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
173156

174-
class WgRfcFactory(WgDraftFactory):
157+
class IndividualRfcFactory(RfcFactory):
158+
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
175159

176-
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
177160

178-
std_level_id = 'ps'
161+
class WgDraftFactory(BaseDocumentFactory):
162+
type_id = 'draft'
163+
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='wg')
164+
stream_id = 'ietf'
179165

180166
@factory.post_generation
181167
def states(obj, create, extracted, **kwargs):
@@ -185,16 +171,18 @@ def states(obj, create, extracted, **kwargs):
185171
for (state_type_id,state_slug) in extracted:
186172
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
187173
if not obj.get_state('draft-iesg'):
188-
obj.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
174+
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
189175
else:
190-
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
191-
obj.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
176+
obj.set_state(State.objects.get(type_id='draft',slug='active'))
177+
obj.set_state(State.objects.get(type_id='draft-stream-ietf',slug='wg-doc'))
178+
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
179+
180+
181+
class WgRfcFactory(RfcFactory):
182+
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='wg')
183+
stream_id = 'ietf'
184+
std_level_id = 'ps'
192185

193-
@factory.post_generation
194-
def reset_canonical_name(obj, create, extracted, **kwargs):
195-
if hasattr(obj, '_canonical_name'):
196-
del obj._canonical_name
197-
return None
198186

199187
class RgDraftFactory(BaseDocumentFactory):
200188

@@ -217,34 +205,11 @@ def states(obj, create, extracted, **kwargs):
217205
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
218206

219207

220-
class RgRfcFactory(RgDraftFactory):
221-
222-
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
223-
208+
class RgRfcFactory(RfcFactory):
209+
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='rg')
210+
stream_id = 'irtf'
224211
std_level_id = 'inf'
225212

226-
@factory.post_generation
227-
def states(obj, create, extracted, **kwargs):
228-
if not create:
229-
return
230-
if extracted:
231-
for (state_type_id,state_slug) in extracted:
232-
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
233-
if not obj.get_state('draft-stream-irtf'):
234-
obj.set_state(State.objects.get(type_id='draft-stream-irtf', slug='pub'))
235-
if not obj.get_state('draft-iesg'):
236-
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
237-
else:
238-
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
239-
obj.set_state(State.objects.get(type_id='draft-stream-irtf', slug='pub'))
240-
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
241-
242-
@factory.post_generation
243-
def reset_canonical_name(obj, create, extracted, **kwargs):
244-
if hasattr(obj, '_canonical_name'):
245-
del obj._canonical_name
246-
return None
247-
248213

249214
class CharterFactory(BaseDocumentFactory):
250215

@@ -545,30 +510,5 @@ def states(obj, create, extracted, **kwargs):
545510
obj.set_state(State.objects.get(type_id='draft-stream-editorial',slug='active'))
546511
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
547512

548-
class EditorialRfcFactory(RgDraftFactory):
549-
550-
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
551-
552-
std_level_id = 'inf'
553-
554-
@factory.post_generation
555-
def states(obj, create, extracted, **kwargs):
556-
if not create:
557-
return
558-
if extracted:
559-
for (state_type_id,state_slug) in extracted:
560-
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
561-
if not obj.get_state('draft-stream-editorial'):
562-
obj.set_state(State.objects.get(type_id='draft-stream-editorial', slug='pub'))
563-
if not obj.get_state('draft-iesg'):
564-
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
565-
else:
566-
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
567-
obj.set_state(State.objects.get(type_id='draft-stream-editorial', slug='pub'))
568-
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
569-
570-
@factory.post_generation
571-
def reset_canonical_name(obj, create, extracted, **kwargs):
572-
if hasattr(obj, '_canonical_name'):
573-
del obj._canonical_name
574-
return None
513+
class EditorialRfcFactory(RgRfcFactory):
514+
pass

ietf/doc/forms.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def clean(self):
175175
drafts = self.cleaned_data['drafts']
176176
for d in drafts:
177177
if RelatedDocument.objects.filter(source=d, target=rfc, relationship_id='downref-approval'):
178-
v_err_pairs.append(d.name + " --> RFC " + rfc.rfc_number())
178+
v_err_pairs.append(f"{d.name} --> RFC {rfc.rfc_number}")
179179
if v_err_pairs:
180180
raise forms.ValidationError("Downref is already in the registry: " + ", ".join(v_err_pairs))
181181

@@ -189,7 +189,8 @@ def clean(self):
189189
else:
190190
v_err_refnorm = d.name
191191
if v_err_refnorm:
192-
v_err_refnorm_prefix = "There does not seem to be a normative reference to RFC " + rfc.rfc_number() + " by "
192+
v_err_refnorm_prefix = f"There does not seem to be a normative reference to RFC {rfc.rfc_number} by "
193+
v_err_refnorm_prefix = f"There does not seem to be a normative reference to RFC {rfc.document.rfc_number} by "
193194
raise forms.ValidationError(v_err_refnorm_prefix + v_err_refnorm)
194195

195196

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 4.2.2 on 2023-06-14 20:57
2+
3+
from django.db import migrations
4+
5+
6+
def forward(apps, schema_editor):
7+
StateType = apps.get_model("doc", "StateType")
8+
rfc_statetype, _ = StateType.objects.get_or_create(slug="rfc", label="State")
9+
10+
State = apps.get_model("doc", "State")
11+
State.objects.get_or_create(
12+
type=rfc_statetype, slug="published", name="Published", used=True, order=1
13+
)
14+
15+
16+
class Migration(migrations.Migration):
17+
dependencies = [
18+
("doc", "0004_alter_dochistory_ad_alter_dochistory_shepherd_and_more"),
19+
]
20+
21+
operations = [
22+
migrations.RunPython(forward),
23+
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 4.2.2 on 2023-06-14 22:28
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("doc", "0005_add_rfc_states"),
9+
]
10+
11+
operations = [
12+
migrations.AddField(
13+
model_name="dochistory",
14+
name="rfc_number",
15+
field=models.PositiveIntegerField(blank=True, null=True),
16+
),
17+
migrations.AddField(
18+
model_name="document",
19+
name="rfc_number",
20+
field=models.PositiveIntegerField(blank=True, null=True),
21+
),
22+
]
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Generated by Django 4.2.2 on 2023-06-15 15:27
2+
3+
from django.db import migrations
4+
5+
6+
def forward(apps, schema_editor):
7+
Document = apps.get_model("doc", "Document")
8+
DocAlias = apps.get_model("doc", "DocAlias")
9+
DocumentAuthor = apps.get_model("doc", "DocumentAuthor")
10+
11+
State = apps.get_model("doc", "State")
12+
draft_rfc_state = State.objects.get(type_id="draft", slug="rfc")
13+
rfc_published_state = State.objects.get(type_id="rfc", slug="published")
14+
15+
DocTypeName = apps.get_model("name", "DocTypeName")
16+
rfc_doctype = DocTypeName(slug="rfc")
17+
18+
# Find draft Documents in the "rfc" state
19+
found_by_state = Document.objects.filter(states=draft_rfc_state).distinct()
20+
21+
# Find Documents with an "rfc..." alias and confirm they're the same set
22+
rfc_docaliases = DocAlias.objects.filter(name__startswith="rfc")
23+
found_by_name = Document.objects.filter(docalias__in=rfc_docaliases).distinct()
24+
assert set(found_by_name) == set(found_by_state), "mismatch between rfcs identified by state and docalias"
25+
26+
# As of 2023-06-15, there is one Document with two rfc aliases: rfc6312 and rfc6342 are the same Document. This
27+
# was due to a publication error. We'll handle that specially.
28+
29+
for rfc_alias in rfc_docaliases.order_by("name"):
30+
assert rfc_alias.docs.count() == 1, f"DocAlias {rfc_alias} is linked to more than 1 Document"
31+
draft = rfc_alias.docs.first()
32+
if draft.name.startswith("rfc"):
33+
rfc = draft
34+
rfc.type = rfc_doctype
35+
rfc.rfc_number = int(draft.name[3:])
36+
rfc.save()
37+
rfc.states.set([rfc_published_state])
38+
else:
39+
rfc = Document.objects.create(
40+
type=rfc_doctype,
41+
name=rfc_alias.name,
42+
rfc_number=int(rfc_alias.name[3:]),
43+
title=draft.title,
44+
abstract=draft.abstract,
45+
pages=draft.pages,
46+
words=draft.words,
47+
std_level=draft.std_level,
48+
external_url=draft.external_url,
49+
uploaded_filename=draft.uploaded_filename,
50+
note=draft.note,
51+
)
52+
rfc.states.set([rfc_published_state])
53+
rfc.formal_languages.set(draft.formal_languages.all())
54+
55+
# Copy Authors
56+
for da in draft.documentauthor_set.all():
57+
DocumentAuthor.objects.create(
58+
document=rfc,
59+
person=da.person,
60+
email=da.email,
61+
affiliation=da.affiliation,
62+
country=da.country,
63+
order=da.order,
64+
)
65+
66+
67+
class Migration(migrations.Migration):
68+
dependencies = [
69+
("doc", "0006_dochistory_rfc_number_document_rfc_number"),
70+
("name", "0004_rfc_doctype_names"),
71+
]
72+
73+
operations = [
74+
migrations.RunPython(forward),
75+
]

0 commit comments

Comments
 (0)