Skip to content

Commit 12adda7

Browse files
ci: merge main to release
2 parents 4e8db54 + 752c6e5 commit 12adda7

6 files changed

Lines changed: 67 additions & 66 deletions

File tree

ietf/api/serializers_rpc.py

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
update_rfcauthors,
2828
)
2929
from ietf.group.models import Group
30-
from ietf.name.models import StreamName, StdLevelName, FormalLanguageName
30+
from ietf.name.models import StreamName, StdLevelName
3131
from ietf.person.models import Person
3232
from ietf.utils import log
3333

@@ -114,11 +114,14 @@ class FullDraftSerializer(serializers.ModelSerializer):
114114
# is used for a writeable view, the validation will need to be added back.
115115
name = serializers.CharField(max_length=255)
116116
title = serializers.CharField(max_length=255)
117+
group = serializers.SlugRelatedField(slug_field="acronym", read_only=True)
117118

118119
# Other fields we need to add / adjust
119120
source_format = serializers.SerializerMethodField()
120121
authors = DocumentAuthorSerializer(many=True, source="documentauthor_set")
121-
shepherd = serializers.SerializerMethodField()
122+
shepherd = serializers.PrimaryKeyRelatedField(
123+
source="shepherd.person", read_only=True
124+
)
122125
consensus = serializers.SerializerMethodField()
123126

124127
class Meta:
@@ -129,12 +132,15 @@ class Meta:
129132
"rev",
130133
"stream",
131134
"title",
135+
"group",
136+
"abstract",
132137
"pages",
133138
"source_format",
134139
"authors",
135-
"shepherd",
136140
"intended_std_level",
137141
"consensus",
142+
"shepherd",
143+
"ad",
138144
]
139145

140146
def get_consensus(self, doc: Document) -> Optional[bool]:
@@ -155,12 +161,6 @@ def get_source_format(
155161
return "txt"
156162
return "unknown"
157163

158-
@extend_schema_field(OpenApiTypes.EMAIL)
159-
def get_shepherd(self, doc: Document) -> str:
160-
if doc.shepherd:
161-
return doc.shepherd.formatted_ascii_email()
162-
return ""
163-
164164

165165
class DraftSerializer(FullDraftSerializer):
166166
class Meta:
@@ -171,9 +171,11 @@ class Meta:
171171
"rev",
172172
"stream",
173173
"title",
174+
"group",
174175
"pages",
175176
"source_format",
176177
"authors",
178+
"consensus",
177179
]
178180

179181

@@ -261,15 +263,6 @@ class RfcPubSerializer(serializers.ModelSerializer):
261263
stream = serializers.PrimaryKeyRelatedField(
262264
queryset=StreamName.objects.filter(used=True)
263265
)
264-
formal_languages = serializers.PrimaryKeyRelatedField(
265-
many=True,
266-
required=False,
267-
queryset=FormalLanguageName.objects.filter(used=True),
268-
help_text=(
269-
"formal languages used in RFC (defaults to those from draft, send empty"
270-
"list to override)"
271-
)
272-
)
273266
std_level = serializers.PrimaryKeyRelatedField(
274267
queryset=StdLevelName.objects.filter(used=True),
275268
)
@@ -313,11 +306,8 @@ class Meta:
313306
"stream",
314307
"abstract",
315308
"pages",
316-
"words",
317-
"formal_languages",
318309
"std_level",
319310
"ad",
320-
"note",
321311
"obsoletes",
322312
"updates",
323313
"subseries",
@@ -351,9 +341,6 @@ def create(self, validated_data):
351341
# If specified, retrieve draft and extract RFC default values from it
352342
if draft_name is None:
353343
draft = None
354-
defaults_from_draft = {
355-
"group": Group.objects.get(acronym="none", type_id="individ"),
356-
}
357344
else:
358345
# validation enforces that draft_name and draft_rev are both present
359346
draft = Document.objects.filter(
@@ -376,17 +363,11 @@ def create(self, validated_data):
376363
},
377364
code="already-published-draft",
378365
)
379-
defaults_from_draft = {
380-
"ad": draft.ad,
381-
"formal_languages": draft.formal_languages.all(),
382-
"group": draft.group,
383-
"note": draft.note,
384-
}
385366

386367
# Transaction to clean up if something fails
387368
with transaction.atomic():
388369
# create rfc, letting validated request data override draft defaults
389-
rfc = self._create_rfc(defaults_from_draft | validated_data)
370+
rfc = self._create_rfc(validated_data)
390371
DocEvent.objects.create(
391372
doc=rfc,
392373
rev=rfc.rev,
@@ -521,14 +502,11 @@ def create(self, validated_data):
521502

522503
def _create_rfc(self, validated_data):
523504
authors_data = validated_data.pop("authors")
524-
formal_languages = validated_data.pop("formal_languages", [])
525-
# todo ad field
526505
rfc = Document.objects.create(
527506
type_id="rfc",
528507
name=f"rfc{validated_data['rfc_number']}",
529508
**validated_data,
530509
)
531-
rfc.formal_languages.set(formal_languages) # list of PKs is ok
532510
for order, author_data in enumerate(authors_data):
533511
rfc.rfcauthor_set.create(
534512
order=order,

ietf/api/tests_views_rpc.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,15 @@ def test_draftviewset_references(self):
8080
def test_notify_rfc_published(self):
8181
url = urlreverse("ietf.api.purple_api.notify_rfc_published")
8282
area = GroupFactory(type_id="area")
83+
rfc_group = GroupFactory(type_id="wg")
8384
draft_ad = RoleFactory(group=area, name_id="ad").person
84-
authors = PersonFactory.create_batch(2)
85-
draft = WgDraftFactory(group__parent=area, authors=authors)
85+
rfc_ad = PersonFactory()
86+
draft_authors = PersonFactory.create_batch(2)
87+
rfc_authors = PersonFactory.create_batch(3)
88+
draft = WgDraftFactory(
89+
group__parent=area, authors=draft_authors, ad=draft_ad, stream_id="ietf"
90+
)
91+
rfc_stream_id = "ise"
8692
assert isinstance(draft, Document), "WgDraftFactory should generate a Document"
8793
unused_rfc_number = (
8894
Document.objects.filter(rfc_number__isnull=False).aggregate(
@@ -96,7 +102,7 @@ def test_notify_rfc_published(self):
96102
"draft_name": draft.name,
97103
"draft_rev": draft.rev,
98104
"rfc_number": unused_rfc_number,
99-
"title": draft.title,
105+
"title": "RFC " + draft.title,
100106
"authors": [
101107
{
102108
"titlepage_name": f"titlepage {author.name}",
@@ -106,17 +112,14 @@ def test_notify_rfc_published(self):
106112
"affiliation": "Some Affiliation",
107113
"country": "CA",
108114
}
109-
for author in authors
115+
for author in rfc_authors
110116
],
111-
"group": draft.group.acronym,
112-
"stream": draft.stream_id,
113-
"abstract": draft.abstract,
114-
"pages": draft.pages,
115-
"words": draft.pages * 250,
116-
"formal_languages": [],
117+
"group": rfc_group.acronym,
118+
"stream": rfc_stream_id,
119+
"abstract": "RFC version of " + draft.abstract,
120+
"pages": draft.pages + 10,
117121
"std_level": "ps",
118-
"ad": draft_ad.pk,
119-
"note": "noted",
122+
"ad": rfc_ad.pk,
120123
"obsoletes": [],
121124
"updates": [],
122125
"subseries": [],
@@ -137,7 +140,7 @@ def test_notify_rfc_published(self):
137140
).count(),
138141
1,
139142
)
140-
self.assertEqual(rfc.title, draft.title)
143+
self.assertEqual(rfc.title, "RFC " + draft.title)
141144
self.assertEqual(rfc.documentauthor_set.count(), 0)
142145
self.assertEqual(
143146
list(
@@ -159,18 +162,15 @@ def test_notify_rfc_published(self):
159162
"affiliation": "Some Affiliation",
160163
"country": "CA",
161164
}
162-
for author in authors
165+
for author in rfc_authors
163166
],
164167
)
165-
self.assertEqual(rfc.group, draft.group)
166-
self.assertEqual(rfc.stream, draft.stream)
167-
self.assertEqual(rfc.abstract, draft.abstract)
168-
self.assertEqual(rfc.pages, draft.pages)
169-
self.assertEqual(rfc.words, draft.pages * 250)
170-
self.assertEqual(rfc.formal_languages.count(), 0)
168+
self.assertEqual(rfc.group, rfc_group)
169+
self.assertEqual(rfc.stream_id, rfc_stream_id)
170+
self.assertEqual(rfc.abstract, "RFC version of " + draft.abstract)
171+
self.assertEqual(rfc.pages, draft.pages + 10)
171172
self.assertEqual(rfc.std_level_id, "ps")
172-
self.assertEqual(rfc.ad, draft_ad)
173-
self.assertEqual(rfc.note, "noted")
173+
self.assertEqual(rfc.ad, rfc_ad)
174174
self.assertEqual(rfc.related_that_doc("obs"), [])
175175
self.assertEqual(rfc.related_that_doc("updates"), [])
176176
self.assertEqual(rfc.part_of(), [])

ietf/api/views_rpc.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from tempfile import TemporaryDirectory
66

77
from django.conf import settings
8+
from django.db import IntegrityError
89
from drf_spectacular.utils import OpenApiParameter
910
from rest_framework import mixins, parsers, serializers, viewsets, status
1011
from rest_framework.decorators import action
@@ -360,7 +361,20 @@ def post(self, request):
360361
serializer = RfcPubSerializer(data=request.data)
361362
serializer.is_valid(raise_exception=True)
362363
# Create RFC
363-
serializer.save()
364+
try:
365+
serializer.save()
366+
except IntegrityError as err:
367+
if Document.objects.filter(
368+
rfc_number=serializer.validated_data["rfc_number"]
369+
):
370+
raise serializers.ValidationError(
371+
"RFC with that number already exists",
372+
code="rfc-number-in-use",
373+
)
374+
raise serializers.ValidationError(
375+
f"Unable to publish: {err}",
376+
code="unknown-integrity-error",
377+
)
364378
return Response(NotificationAckSerializer().data)
365379

366380

ietf/doc/tests_bofreq.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,17 +307,20 @@ def test_submit(self):
307307
url = urlreverse('ietf.doc.views_bofreq.submit', kwargs=dict(name=doc.name))
308308

309309
rev = doc.rev
310+
doc_time = doc.time
310311
r = self.client.post(url,{'bofreq_submission':'enter','bofreq_content':'# oiwefrase'})
311312
self.assertEqual(r.status_code, 302)
312313
doc = reload_db_objects(doc)
313-
self.assertEqual(rev, doc.rev)
314+
self.assertEqual(doc.rev, rev)
315+
self.assertEqual(doc.time, doc_time)
314316

315317
nobody = PersonFactory()
316318
self.client.login(username=nobody.user.username, password=nobody.user.username+'+password')
317319
r = self.client.post(url,{'bofreq_submission':'enter','bofreq_content':'# oiwefrase'})
318320
self.assertEqual(r.status_code, 403)
319321
doc = reload_db_objects(doc)
320-
self.assertEqual(rev, doc.rev)
322+
self.assertEqual(doc.rev, rev)
323+
self.assertEqual(doc.time, doc_time)
321324
self.client.logout()
322325

323326
editor = bofreq_editors(doc).first()
@@ -339,12 +342,14 @@ def test_submit(self):
339342
r = self.client.post(url, postdict)
340343
self.assertEqual(r.status_code, 302)
341344
doc = reload_db_objects(doc)
342-
self.assertEqual('%02d'%(int(rev)+1) ,doc.rev)
343-
self.assertEqual(f'# {username}', doc.text())
344-
self.assertEqual(f'# {username}', retrieve_str('bofreq',doc.get_base_name()))
345-
self.assertEqual(docevent_count+1, doc.docevent_set.count())
346-
self.assertEqual(1, len(outbox))
345+
self.assertEqual(doc.rev, '%02d'%(int(rev)+1))
346+
self.assertGreater(doc.time, doc_time)
347+
self.assertEqual(doc.text(), f'# {username}')
348+
self.assertEqual(retrieve_str('bofreq', doc.get_base_name()), f'# {username}')
349+
self.assertEqual(doc.docevent_set.count(), docevent_count+1)
350+
self.assertEqual(len(outbox), 1)
347351
rev = doc.rev
352+
doc_time = doc.time
348353
finally:
349354
os.unlink(file.name)
350355

ietf/doc/views_bofreq.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ def submit(request, name):
9191
by=request.user.person,
9292
rev=bofreq.rev,
9393
desc='New revision available',
94-
time=bofreq.time,
9594
)
9695
bofreq.save_with_history([e])
9796
bofreq_submission = form.cleaned_data['bofreq_submission']

ietf/message/admin.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ def queryset(self, request, queryset):
2727

2828

2929
class MessageAdmin(admin.ModelAdmin):
30-
list_display = ["sent_status", "subject", "by", "time", "groups"]
30+
list_display = ["sent_status", "display_subject", "by", "time", "groups"]
31+
list_display_links = ["display_subject"]
3132
search_fields = ["subject", "body"]
3233
raw_id_fields = ["by", "related_groups", "related_docs"]
3334
list_filter = [
@@ -37,6 +38,10 @@ class MessageAdmin(admin.ModelAdmin):
3738
ordering = ["-time"]
3839
actions = ["retry_send"]
3940

41+
@admin.display(description="Subject", empty_value="(no subject)")
42+
def display_subject(self, instance):
43+
return instance.subject or None # None triggers the empty_value
44+
4045
def groups(self, instance):
4146
return ", ".join(g.acronym for g in instance.related_groups.all())
4247

0 commit comments

Comments
 (0)