Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 12 additions & 34 deletions ietf/api/serializers_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
update_rfcauthors,
)
from ietf.group.models import Group
from ietf.name.models import StreamName, StdLevelName, FormalLanguageName
from ietf.name.models import StreamName, StdLevelName
from ietf.person.models import Person
from ietf.utils import log

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

# Other fields we need to add / adjust
source_format = serializers.SerializerMethodField()
authors = DocumentAuthorSerializer(many=True, source="documentauthor_set")
shepherd = serializers.SerializerMethodField()
shepherd = serializers.PrimaryKeyRelatedField(
source="shepherd.person", read_only=True
)
consensus = serializers.SerializerMethodField()

class Meta:
Expand All @@ -129,12 +132,15 @@ class Meta:
"rev",
"stream",
"title",
"group",
"abstract",
"pages",
"source_format",
"authors",
"shepherd",
"intended_std_level",
"consensus",
"shepherd",
"ad",
]

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

@extend_schema_field(OpenApiTypes.EMAIL)
def get_shepherd(self, doc: Document) -> str:
if doc.shepherd:
return doc.shepherd.formatted_ascii_email()
return ""


class DraftSerializer(FullDraftSerializer):
class Meta:
Expand All @@ -171,9 +171,11 @@ class Meta:
"rev",
"stream",
"title",
"group",
"pages",
"source_format",
"authors",
"consensus",
]


Expand Down Expand Up @@ -261,15 +263,6 @@ class RfcPubSerializer(serializers.ModelSerializer):
stream = serializers.PrimaryKeyRelatedField(
queryset=StreamName.objects.filter(used=True)
)
formal_languages = serializers.PrimaryKeyRelatedField(
many=True,
required=False,
queryset=FormalLanguageName.objects.filter(used=True),
help_text=(
"formal languages used in RFC (defaults to those from draft, send empty"
"list to override)"
)
)
std_level = serializers.PrimaryKeyRelatedField(
queryset=StdLevelName.objects.filter(used=True),
)
Expand Down Expand Up @@ -313,11 +306,8 @@ class Meta:
"stream",
"abstract",
"pages",
"words",
"formal_languages",
"std_level",
"ad",
"note",
"obsoletes",
"updates",
"subseries",
Expand Down Expand Up @@ -351,9 +341,6 @@ def create(self, validated_data):
# If specified, retrieve draft and extract RFC default values from it
if draft_name is None:
draft = None
defaults_from_draft = {
"group": Group.objects.get(acronym="none", type_id="individ"),
}
else:
# validation enforces that draft_name and draft_rev are both present
draft = Document.objects.filter(
Expand All @@ -376,17 +363,11 @@ def create(self, validated_data):
},
code="already-published-draft",
)
defaults_from_draft = {
"ad": draft.ad,
"formal_languages": draft.formal_languages.all(),
"group": draft.group,
"note": draft.note,
}

# Transaction to clean up if something fails
with transaction.atomic():
# create rfc, letting validated request data override draft defaults
rfc = self._create_rfc(defaults_from_draft | validated_data)
rfc = self._create_rfc(validated_data)
DocEvent.objects.create(
doc=rfc,
rev=rfc.rev,
Expand Down Expand Up @@ -521,14 +502,11 @@ def create(self, validated_data):

def _create_rfc(self, validated_data):
authors_data = validated_data.pop("authors")
formal_languages = validated_data.pop("formal_languages", [])
# todo ad field
rfc = Document.objects.create(
type_id="rfc",
name=f"rfc{validated_data['rfc_number']}",
**validated_data,
)
rfc.formal_languages.set(formal_languages) # list of PKs is ok
for order, author_data in enumerate(authors_data):
rfc.rfcauthor_set.create(
order=order,
Expand Down
44 changes: 22 additions & 22 deletions ietf/api/tests_views_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,15 @@ def test_draftviewset_references(self):
def test_notify_rfc_published(self):
url = urlreverse("ietf.api.purple_api.notify_rfc_published")
area = GroupFactory(type_id="area")
rfc_group = GroupFactory(type_id="wg")
draft_ad = RoleFactory(group=area, name_id="ad").person
authors = PersonFactory.create_batch(2)
draft = WgDraftFactory(group__parent=area, authors=authors)
rfc_ad = PersonFactory()
draft_authors = PersonFactory.create_batch(2)
rfc_authors = PersonFactory.create_batch(3)
draft = WgDraftFactory(
group__parent=area, authors=draft_authors, ad=draft_ad, stream_id="ietf"
)
rfc_stream_id = "ise"
assert isinstance(draft, Document), "WgDraftFactory should generate a Document"
unused_rfc_number = (
Document.objects.filter(rfc_number__isnull=False).aggregate(
Expand All @@ -96,7 +102,7 @@ def test_notify_rfc_published(self):
"draft_name": draft.name,
"draft_rev": draft.rev,
"rfc_number": unused_rfc_number,
"title": draft.title,
"title": "RFC " + draft.title,
"authors": [
{
"titlepage_name": f"titlepage {author.name}",
Expand All @@ -106,17 +112,14 @@ def test_notify_rfc_published(self):
"affiliation": "Some Affiliation",
"country": "CA",
}
for author in authors
for author in rfc_authors
],
"group": draft.group.acronym,
"stream": draft.stream_id,
"abstract": draft.abstract,
"pages": draft.pages,
"words": draft.pages * 250,
"formal_languages": [],
"group": rfc_group.acronym,
"stream": rfc_stream_id,
"abstract": "RFC version of " + draft.abstract,
"pages": draft.pages + 10,
"std_level": "ps",
"ad": draft_ad.pk,
"note": "noted",
"ad": rfc_ad.pk,
"obsoletes": [],
"updates": [],
"subseries": [],
Expand All @@ -137,7 +140,7 @@ def test_notify_rfc_published(self):
).count(),
1,
)
self.assertEqual(rfc.title, draft.title)
self.assertEqual(rfc.title, "RFC " + draft.title)
self.assertEqual(rfc.documentauthor_set.count(), 0)
self.assertEqual(
list(
Expand All @@ -159,18 +162,15 @@ def test_notify_rfc_published(self):
"affiliation": "Some Affiliation",
"country": "CA",
}
for author in authors
for author in rfc_authors
],
)
self.assertEqual(rfc.group, draft.group)
self.assertEqual(rfc.stream, draft.stream)
self.assertEqual(rfc.abstract, draft.abstract)
self.assertEqual(rfc.pages, draft.pages)
self.assertEqual(rfc.words, draft.pages * 250)
self.assertEqual(rfc.formal_languages.count(), 0)
self.assertEqual(rfc.group, rfc_group)
self.assertEqual(rfc.stream_id, rfc_stream_id)
self.assertEqual(rfc.abstract, "RFC version of " + draft.abstract)
self.assertEqual(rfc.pages, draft.pages + 10)
self.assertEqual(rfc.std_level_id, "ps")
self.assertEqual(rfc.ad, draft_ad)
self.assertEqual(rfc.note, "noted")
self.assertEqual(rfc.ad, rfc_ad)
self.assertEqual(rfc.related_that_doc("obs"), [])
self.assertEqual(rfc.related_that_doc("updates"), [])
self.assertEqual(rfc.part_of(), [])
Expand Down
16 changes: 15 additions & 1 deletion ietf/api/views_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from tempfile import TemporaryDirectory

from django.conf import settings
from django.db import IntegrityError
from drf_spectacular.utils import OpenApiParameter
from rest_framework import mixins, parsers, serializers, viewsets, status
from rest_framework.decorators import action
Expand Down Expand Up @@ -360,7 +361,20 @@ def post(self, request):
serializer = RfcPubSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
# Create RFC
serializer.save()
try:
serializer.save()
except IntegrityError as err:
if Document.objects.filter(
rfc_number=serializer.validated_data["rfc_number"]
):
raise serializers.ValidationError(
"RFC with that number already exists",
code="rfc-number-in-use",
)
raise serializers.ValidationError(
f"Unable to publish: {err}",
code="unknown-integrity-error",
)
return Response(NotificationAckSerializer().data)


Expand Down
19 changes: 12 additions & 7 deletions ietf/doc/tests_bofreq.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,17 +307,20 @@ def test_submit(self):
url = urlreverse('ietf.doc.views_bofreq.submit', kwargs=dict(name=doc.name))

rev = doc.rev
doc_time = doc.time
r = self.client.post(url,{'bofreq_submission':'enter','bofreq_content':'# oiwefrase'})
self.assertEqual(r.status_code, 302)
doc = reload_db_objects(doc)
self.assertEqual(rev, doc.rev)
self.assertEqual(doc.rev, rev)
self.assertEqual(doc.time, doc_time)

nobody = PersonFactory()
self.client.login(username=nobody.user.username, password=nobody.user.username+'+password')
r = self.client.post(url,{'bofreq_submission':'enter','bofreq_content':'# oiwefrase'})
self.assertEqual(r.status_code, 403)
doc = reload_db_objects(doc)
self.assertEqual(rev, doc.rev)
self.assertEqual(doc.rev, rev)
self.assertEqual(doc.time, doc_time)
self.client.logout()

editor = bofreq_editors(doc).first()
Expand All @@ -339,12 +342,14 @@ def test_submit(self):
r = self.client.post(url, postdict)
self.assertEqual(r.status_code, 302)
doc = reload_db_objects(doc)
self.assertEqual('%02d'%(int(rev)+1) ,doc.rev)
self.assertEqual(f'# {username}', doc.text())
self.assertEqual(f'# {username}', retrieve_str('bofreq',doc.get_base_name()))
self.assertEqual(docevent_count+1, doc.docevent_set.count())
self.assertEqual(1, len(outbox))
self.assertEqual(doc.rev, '%02d'%(int(rev)+1))
self.assertGreater(doc.time, doc_time)
self.assertEqual(doc.text(), f'# {username}')
self.assertEqual(retrieve_str('bofreq', doc.get_base_name()), f'# {username}')
self.assertEqual(doc.docevent_set.count(), docevent_count+1)
self.assertEqual(len(outbox), 1)
rev = doc.rev
doc_time = doc.time
finally:
os.unlink(file.name)

Expand Down
1 change: 0 additions & 1 deletion ietf/doc/views_bofreq.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ def submit(request, name):
by=request.user.person,
rev=bofreq.rev,
desc='New revision available',
time=bofreq.time,
)
bofreq.save_with_history([e])
bofreq_submission = form.cleaned_data['bofreq_submission']
Expand Down
7 changes: 6 additions & 1 deletion ietf/message/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def queryset(self, request, queryset):


class MessageAdmin(admin.ModelAdmin):
list_display = ["sent_status", "subject", "by", "time", "groups"]
list_display = ["sent_status", "display_subject", "by", "time", "groups"]
list_display_links = ["display_subject"]
search_fields = ["subject", "body"]
raw_id_fields = ["by", "related_groups", "related_docs"]
list_filter = [
Expand All @@ -37,6 +38,10 @@ class MessageAdmin(admin.ModelAdmin):
ordering = ["-time"]
actions = ["retry_send"]

@admin.display(description="Subject", empty_value="(no subject)")
def display_subject(self, instance):
return instance.subject or None # None triggers the empty_value

def groups(self, instance):
return ", ".join(g.acronym for g in instance.related_groups.all())

Expand Down