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
25 changes: 13 additions & 12 deletions ietf/api/tests_views_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,22 +143,23 @@ def test_notify_rfc_published(self):
self.assertEqual(rfc.title, "RFC " + draft.title)
self.assertEqual(rfc.documentauthor_set.count(), 0)
self.assertEqual(
list(
rfc.rfcauthor_set.values(
"titlepage_name",
"is_editor",
"person",
"email",
"affiliation",
"country",
)
),
[
{
"titlepage_name": ra.titlepage_name,
"is_editor": ra.is_editor,
"person": ra.person,
"email": ra.email,
"affiliation": ra.affiliation,
"country": ra.country,
}
for ra in rfc.rfcauthor_set.all()
],
[
{
"titlepage_name": f"titlepage {author.name}",
"is_editor": False,
"person": author.pk,
"email": author.email_address(),
"person": author,
"email": author.email(),
"affiliation": "Some Affiliation",
"country": "CA",
}
Expand Down
4 changes: 2 additions & 2 deletions ietf/doc/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,6 @@ def is_deleted(self, instance):

class RfcAuthorAdmin(admin.ModelAdmin):
list_display = ['id', 'document', 'titlepage_name', 'person', 'email', 'affiliation', 'country', 'order']
search_fields = ['document__name', 'titlepage_name', 'person__name', 'email__address', 'affiliation', 'country']
raw_id_fields = ["document", "person", "email"]
search_fields = ['document__name', 'titlepage_name', 'person__name', 'email', 'affiliation', 'country']
raw_id_fields = ["document", "person"]
admin.site.register(RfcAuthor, RfcAuthorAdmin)
10 changes: 9 additions & 1 deletion ietf/doc/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,21 @@ class RfcLimitOffsetPagination(LimitOffsetPagination):
max_limit = 500


class NumberInFilter(filters.BaseInFilter, filters.NumberFilter):
"""Filter against a comma-separated list of numbers"""
pass


class RfcFilter(filters.FilterSet):
published = filters.DateFromToRangeFilter()
stream = filters.ModelMultipleChoiceFilter(
queryset=StreamName.objects.filter(used=True)
)
number = NumberInFilter(
field_name="rfc_number"
)
group = filters.ModelMultipleChoiceFilter(
queryset=Group.objects.wgs(),
queryset=Group.objects.all(),
field_name="group__acronym",
to_field_name="acronym",
)
Expand Down
1 change: 0 additions & 1 deletion ietf/doc/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,6 @@ class Meta:
lambda obj: " ".join([obj.person.initials(), obj.person.last_name()])
)
person = factory.SubFactory('ietf.person.factories.PersonFactory')
email = factory.LazyAttribute(lambda obj: obj.person.email())
affiliation = factory.Faker('company')
order = factory.LazyAttribute(lambda o: o.document.rfcauthor_set.count() + 1)

Expand Down
16 changes: 16 additions & 0 deletions ietf/doc/migrations/0031_remove_rfcauthor_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright The IETF Trust 2026, All Rights Reserved

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("doc", "0030_alter_dochistory_title_alter_document_title"),
]

operations = [
migrations.RemoveField(
model_name="rfcauthor",
name="email",
),
]
6 changes: 5 additions & 1 deletion ietf/doc/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,6 @@ class RfcAuthor(models.Model):
titlepage_name = models.CharField(max_length=128, blank=False)
is_editor = models.BooleanField(default=False)
person = ForeignKey(Person, null=True, blank=True, on_delete=models.PROTECT)
email = ForeignKey(Email, help_text="Email address used by author for submission", blank=True, null=True, on_delete=models.PROTECT)
affiliation = models.CharField(max_length=100, blank=True, help_text="Organization/company used by author for submission")
country = models.CharField(max_length=255, blank=True, help_text="Country used by author for submission")
order = models.IntegerField(default=1)
Expand All @@ -951,6 +950,11 @@ class Meta:
models.Index(fields=["document", "order"])
]

@property
def email(self) -> Email | None:
return self.person.email() if self.person else None


class DocumentAuthorInfo(models.Model):
person = ForeignKey(Person)
# email should only be null for some historic documents
Expand Down
50 changes: 40 additions & 10 deletions ietf/doc/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers

from ietf.group.serializers import GroupSerializer
from ietf.group.serializers import (
AreaDirectorSerializer,
AreaSerializer,
GroupSerializer,
)
from ietf.name.serializers import StreamNameSerializer
from ietf.utils import log
from .models import Document, DocumentAuthor, RfcAuthor


class RfcAuthorSerializer(serializers.ModelSerializer):
"""Serializer for an RfcAuthor / DocumentAuthor in a response"""

email = serializers.EmailField(source="email.address", read_only=True)
datatracker_person_path = serializers.URLField(
source="person.get_absolute_url",
required=False,
Expand All @@ -29,7 +35,7 @@ class Meta:
"titlepage_name",
"is_editor",
"person",
"email", # relies on email.pk being email.address
"email",
"affiliation",
"country",
"datatracker_person_path",
Expand All @@ -48,7 +54,6 @@ def to_representation(self, instance):
titlepage_name=document_author.person.plain_name(),
is_editor=False,
person=document_author.person,
email=document_author.email,
affiliation=document_author.affiliation,
country=document_author.country,
order=document_author.order,
Expand Down Expand Up @@ -174,10 +179,16 @@ def to_representation(self, instance: Document):
return super().to_representation(instance=RfcStatus.from_document(instance))


class ShepherdSerializer(serializers.Serializer):
email = serializers.EmailField(source="email_address")


class RelatedDraftSerializer(serializers.Serializer):
id = serializers.IntegerField(source="source.id")
name = serializers.CharField(source="source.name")
title = serializers.CharField(source="source.title")
shepherd = ShepherdSerializer(source="source.shepherd")
ad = AreaDirectorSerializer(source="source.ad")


class RelatedRfcSerializer(serializers.Serializer):
Expand Down Expand Up @@ -205,15 +216,23 @@ class RfcFormatSerializer(serializers.Serializer):


class RfcMetadataSerializer(serializers.ModelSerializer):
"""Serialize metadata of an RFC"""
"""Serialize metadata of an RFC

This needs to be called with a Document queryset that has been processed with
api.augment_rfc_queryset() or it very likely will not work. Some of the typing
refers to Document, but this should really be WithAnnotations[Document, ...].
However, have not been able to make that work yet.
"""

number = serializers.IntegerField(source="rfc_number")
published = serializers.DateField()
status = RfcStatusSerializer(source="*")
authors = serializers.SerializerMethodField()
group = GroupSerializer()
area = GroupSerializer(source="group.area", required=False)
area = AreaSerializer(source="group.area", required=False)
stream = StreamNameSerializer()
ad = AreaDirectorSerializer(read_only=True)
group_list_email = serializers.EmailField(source="group.list_email", read_only=True)
identifiers = serializers.SerializerMethodField()
draft = serializers.SerializerMethodField()
obsoletes = RelatedRfcSerializer(many=True, read_only=True)
Expand All @@ -239,6 +258,8 @@ class Meta:
"group",
"area",
"stream",
"ad",
"group_list_email",
"identifiers",
"obsoletes",
"obsoleted_by",
Expand Down Expand Up @@ -276,11 +297,20 @@ def get_identifiers(self, doc: Document):
return DocIdentifierSerializer(instance=identifiers, many=True).data

@extend_schema_field(RelatedDraftSerializer)
def get_draft(self, object):
try:
related_doc = object.drafts[0]
except IndexError:
return None
def get_draft(self, doc: Document):
if hasattr(doc, "drafts"):
# This is the expected case - drafts is added by a Prefetch in
# the augment_rfc_queryset() method.
try:
related_doc = doc.drafts[0]
except IndexError:
return None
else:
# Fallback in case augment_rfc_queryset() was not called
log.log(
f"Warning: {self.__class__}.get_draft() called without prefetched draft"
)
related_doc = doc.came_from_draft()
return RelatedDraftSerializer(related_doc).data


Expand Down
2 changes: 1 addition & 1 deletion ietf/doc/views_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1657,7 +1657,7 @@ def extract_name(s):
doc.rfcauthor_set
if doc.type_id == "rfc" and doc.rfcauthor_set.exists()
else doc.documentauthor_set
).select_related("person", "email").order_by("order")
).select_related("person").prefetch_related("person__email_set").order_by("order")
data["authors"] = [
{
"name": author.titlepage_name if hasattr(author, "titlepage_name") else author.person.name,
Expand Down
32 changes: 29 additions & 3 deletions ietf/group/serializers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
# Copyright The IETF Trust 2024, All Rights Reserved
# Copyright The IETF Trust 2024-2026, All Rights Reserved
"""django-rest-framework serializers"""

from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers

from .models import Group
from ietf.person.models import Email
from .models import Group, Role


class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = ["acronym", "name", "type"]
fields = ["acronym", "name", "type", "list_email"]


class AreaDirectorSerializer(serializers.Serializer):
"""Serialize an area director

Works with Email or Role
"""

email = serializers.SerializerMethodField()

@extend_schema_field(serializers.EmailField)
def get_email(self, instance: Email | Role):
if isinstance(instance, Role):
return instance.email.email_address()
return instance.email_address()


class AreaSerializer(serializers.ModelSerializer):
ads = AreaDirectorSerializer(many=True, read_only=True)

class Meta:
model = Group
fields = ["acronym", "name", "type", "ads"]
1 change: 0 additions & 1 deletion ietf/nomcom/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2528,7 +2528,6 @@ def test_get_qualified_author_queryset(self):
document=rfc,
person=people[0],
titlepage_name="P. Zero",
email=people[0].email_set.first(),
)
self.assertCountEqual(
get_qualified_author_queryset(base_qs, now - 5 * one_year, now),
Expand Down
Loading