From 21faab8d6f976cdc90586fbdff8e71ecbee4ef93 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 20:06:17 -0400 Subject: [PATCH 01/15] feat: RfcAuthorSerializer.email is current email --- ietf/doc/serializers.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ietf/doc/serializers.py b/ietf/doc/serializers.py index e8d373164b..279421aa7c 100644 --- a/ietf/doc/serializers.py +++ b/ietf/doc/serializers.py @@ -16,6 +16,12 @@ class RfcAuthorSerializer(serializers.ModelSerializer): """Serializer for an RfcAuthor / DocumentAuthor in a response""" + email = serializers.EmailField( + source="person.email_address", + help_text="Author's current email address", + allow_blank=True, + read_only=True + ) datatracker_person_path = serializers.URLField( source="person.get_absolute_url", @@ -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", From 9259c19403805d2fcb558886b1e99fb3a991d0a9 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 20:20:08 -0400 Subject: [PATCH 02/15] refactor: RfcAuthor email field -> property --- ietf/doc/admin.py | 4 ++-- ietf/doc/models.py | 6 +++++- ietf/doc/serializers.py | 8 +------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ietf/doc/admin.py b/ietf/doc/admin.py index f082418935..b604d4f096 100644 --- a/ietf/doc/admin.py +++ b/ietf/doc/admin.py @@ -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) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 8f700bf496..fdf5bd4d70 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -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) @@ -951,6 +950,11 @@ class Meta: models.Index(fields=["document", "order"]) ] + @property + def email(self) -> str: + return self.person.email_address() if self.person else "" + + class DocumentAuthorInfo(models.Model): person = ForeignKey(Person) # email should only be null for some historic documents diff --git a/ietf/doc/serializers.py b/ietf/doc/serializers.py index 279421aa7c..950530b01b 100644 --- a/ietf/doc/serializers.py +++ b/ietf/doc/serializers.py @@ -16,12 +16,6 @@ class RfcAuthorSerializer(serializers.ModelSerializer): """Serializer for an RfcAuthor / DocumentAuthor in a response""" - email = serializers.EmailField( - source="person.email_address", - help_text="Author's current email address", - allow_blank=True, - read_only=True - ) datatracker_person_path = serializers.URLField( source="person.get_absolute_url", @@ -40,6 +34,7 @@ class Meta: "country", "datatracker_person_path", ] + read_only_fields = ["email"] def to_representation(self, instance): """instance -> primitive data types @@ -54,7 +49,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, From b0f57a99807d44307f35b0dc6ad0d10157004fc0 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 22:21:52 -0400 Subject: [PATCH 03/15] feat: more RfcMetadataSerializer fields * shepherd email (with a fallback to the draft) * doc ad email * area ad emails * group list email --- ietf/doc/serializers.py | 39 +++++++++++++++++++++++++++++++++++---- ietf/group/serializers.py | 22 ++++++++++++++++++++-- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/ietf/doc/serializers.py b/ietf/doc/serializers.py index 950530b01b..059aebea1c 100644 --- a/ietf/doc/serializers.py +++ b/ietf/doc/serializers.py @@ -9,7 +9,11 @@ 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 .models import Document, DocumentAuthor, RfcAuthor @@ -204,6 +208,10 @@ class RfcFormatSerializer(serializers.Serializer): name = serializers.CharField(help_text="Name of blob in the blob store") +class ShepherdSerializer(serializers.Serializer): + email = serializers.EmailField(source="formatted_email") + + class RfcMetadataSerializer(serializers.ModelSerializer): """Serialize metadata of an RFC""" @@ -212,8 +220,11 @@ class RfcMetadataSerializer(serializers.ModelSerializer): status = RfcStatusSerializer(source="*") authors = serializers.SerializerMethodField() group = GroupSerializer() - area = GroupSerializer(source="group.area", required=False) + area = AreaSerializer(source="group.area", required=False) stream = StreamNameSerializer() + shepherd = serializers.SerializerMethodField() + ad = AreaDirectorSerializer(source="ad.email", 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) @@ -239,6 +250,9 @@ class Meta: "group", "area", "stream", + "shepherd", + "ad", + "group_list_email", "identifiers", "obsoletes", "obsoleted_by", @@ -276,13 +290,30 @@ def get_identifiers(self, doc: Document): return DocIdentifierSerializer(instance=identifiers, many=True).data @extend_schema_field(RelatedDraftSerializer) - def get_draft(self, object): + def get_draft(self, doc: Document): try: - related_doc = object.drafts[0] + related_doc = doc.drafts[0] except IndexError: return None return RelatedDraftSerializer(related_doc).data + @extend_schema_field(ShepherdSerializer) + def get_shepherd(self, doc: Document): + """Get shepherd, falling back to originating draft if needed + + This could be simplified if we backfilled shepherd for RFC Documents + """ + shepherd = ( + doc.shepherd + if doc.shepherd is not None + else ( + doc.came_from_draft().shepherd + if doc.came_from_draft() is not None + else None + ) + ) + return None if shepherd is None else ShepherdSerializer(shepherd).data + class RfcSerializer(RfcMetadataSerializer): """Serialize an RFC, including its metadata and text content if available""" diff --git a/ietf/group/serializers.py b/ietf/group/serializers.py index 08e6bba81a..733541d4ab 100644 --- a/ietf/group/serializers.py +++ b/ietf/group/serializers.py @@ -1,5 +1,6 @@ -# Copyright The IETF Trust 2024, All Rights Reserved +# Copyright The IETF Trust 2024-2026, All Rights Reserved """django-rest-framework serializers""" + from rest_framework import serializers from .models import Group @@ -8,4 +9,21 @@ 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.EmailField(source="formatted_email") + + +class AreaSerializer(serializers.ModelSerializer): + ads = AreaDirectorSerializer(many=True, read_only=True) + + class Meta: + model = Group + fields = ["acronym", "name", "type", "ads"] From db4b52289c74d763f03f0fdb85ff33998b40cefe Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 22:27:45 -0400 Subject: [PATCH 04/15] fix: filter RFCs by any group type --- ietf/doc/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/doc/api.py b/ietf/doc/api.py index 6a4c0c9fd5..69d93e66d6 100644 --- a/ietf/doc/api.py +++ b/ietf/doc/api.py @@ -48,7 +48,7 @@ class RfcFilter(filters.FilterSet): queryset=StreamName.objects.filter(used=True) ) group = filters.ModelMultipleChoiceFilter( - queryset=Group.objects.wgs(), + queryset=Group.objects.all(), field_name="group__acronym", to_field_name="acronym", ) From 9a6928a196a533c1e7c2f9360d60e13987cd06e3 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 22:45:48 -0400 Subject: [PATCH 05/15] feat: filter by RFC numbers --- ietf/doc/api.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ietf/doc/api.py b/ietf/doc/api.py index 69d93e66d6..f399031744 100644 --- a/ietf/doc/api.py +++ b/ietf/doc/api.py @@ -42,11 +42,19 @@ 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) ) + numbers = NumberInFilter( + field_name="rfc_number" + ) group = filters.ModelMultipleChoiceFilter( queryset=Group.objects.all(), field_name="group__acronym", From 22bac3d6e0dc317aaf85c549079712c49f9c29b8 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 23:01:54 -0400 Subject: [PATCH 06/15] fix: shepherd -> draft object in response JSON --- ietf/doc/serializers.py | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/ietf/doc/serializers.py b/ietf/doc/serializers.py index 059aebea1c..8767d4ee91 100644 --- a/ietf/doc/serializers.py +++ b/ietf/doc/serializers.py @@ -178,10 +178,16 @@ def to_representation(self, instance: Document): return super().to_representation(instance=RfcStatus.from_document(instance)) +class ShepherdSerializer(serializers.Serializer): + email = serializers.EmailField(source="formatted_email") + + 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): @@ -208,10 +214,6 @@ class RfcFormatSerializer(serializers.Serializer): name = serializers.CharField(help_text="Name of blob in the blob store") -class ShepherdSerializer(serializers.Serializer): - email = serializers.EmailField(source="formatted_email") - - class RfcMetadataSerializer(serializers.ModelSerializer): """Serialize metadata of an RFC""" @@ -222,8 +224,7 @@ class RfcMetadataSerializer(serializers.ModelSerializer): group = GroupSerializer() area = AreaSerializer(source="group.area", required=False) stream = StreamNameSerializer() - shepherd = serializers.SerializerMethodField() - ad = AreaDirectorSerializer(source="ad.email", read_only=True) + ad = AreaDirectorSerializer(read_only=True) group_list_email = serializers.EmailField(source="group.list_email", read_only=True) identifiers = serializers.SerializerMethodField() draft = serializers.SerializerMethodField() @@ -250,7 +251,6 @@ class Meta: "group", "area", "stream", - "shepherd", "ad", "group_list_email", "identifiers", @@ -297,23 +297,6 @@ def get_draft(self, doc: Document): return None return RelatedDraftSerializer(related_doc).data - @extend_schema_field(ShepherdSerializer) - def get_shepherd(self, doc: Document): - """Get shepherd, falling back to originating draft if needed - - This could be simplified if we backfilled shepherd for RFC Documents - """ - shepherd = ( - doc.shepherd - if doc.shepherd is not None - else ( - doc.came_from_draft().shepherd - if doc.came_from_draft() is not None - else None - ) - ) - return None if shepherd is None else ShepherdSerializer(shepherd).data - class RfcSerializer(RfcMetadataSerializer): """Serialize an RFC, including its metadata and text content if available""" From 86aa8fadc1892b5ab8f11d87083af26463879773 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 23:17:49 -0400 Subject: [PATCH 07/15] fix: consistent filter naming --- ietf/doc/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/doc/api.py b/ietf/doc/api.py index f399031744..75993f463e 100644 --- a/ietf/doc/api.py +++ b/ietf/doc/api.py @@ -52,7 +52,7 @@ class RfcFilter(filters.FilterSet): stream = filters.ModelMultipleChoiceFilter( queryset=StreamName.objects.filter(used=True) ) - numbers = NumberInFilter( + number = NumberInFilter( field_name="rfc_number" ) group = filters.ModelMultipleChoiceFilter( From 9d3c1cfe5945eb019ae8fdd09ebe22e29f889342 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 19 Feb 2026 23:26:15 -0400 Subject: [PATCH 08/15] chore: migration --- .../migrations/0031_remove_rfcauthor_email.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 ietf/doc/migrations/0031_remove_rfcauthor_email.py diff --git a/ietf/doc/migrations/0031_remove_rfcauthor_email.py b/ietf/doc/migrations/0031_remove_rfcauthor_email.py new file mode 100644 index 0000000000..c4c1911bfe --- /dev/null +++ b/ietf/doc/migrations/0031_remove_rfcauthor_email.py @@ -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", + ), + ] From 2577297bb26c5da3884681f3bda3b25b21551fd5 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 20 Feb 2026 10:51:34 -0400 Subject: [PATCH 09/15] test: update test_notify_rfc_published --- ietf/api/tests_views_rpc.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/ietf/api/tests_views_rpc.py b/ietf/api/tests_views_rpc.py index 09fb40bf6e..7cd300553e 100644 --- a/ietf/api/tests_views_rpc.py +++ b/ietf/api/tests_views_rpc.py @@ -143,21 +143,22 @@ 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, + "person": author, "email": author.email_address(), "affiliation": "Some Affiliation", "country": "CA", From 5684785931ff1f8a4450966dcfd75556e1e22727 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 20 Feb 2026 11:16:04 -0400 Subject: [PATCH 10/15] fix: RfcAuthor.email() -> Email, not str --- ietf/api/tests_views_rpc.py | 2 +- ietf/doc/models.py | 4 ++-- ietf/doc/serializers.py | 2 +- ietf/doc/views_doc.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ietf/api/tests_views_rpc.py b/ietf/api/tests_views_rpc.py index 7cd300553e..1fbb4c3f02 100644 --- a/ietf/api/tests_views_rpc.py +++ b/ietf/api/tests_views_rpc.py @@ -159,7 +159,7 @@ def test_notify_rfc_published(self): "titlepage_name": f"titlepage {author.name}", "is_editor": False, "person": author, - "email": author.email_address(), + "email": author.email(), "affiliation": "Some Affiliation", "country": "CA", } diff --git a/ietf/doc/models.py b/ietf/doc/models.py index fdf5bd4d70..1ad1d36c74 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -951,8 +951,8 @@ class Meta: ] @property - def email(self) -> str: - return self.person.email_address() if self.person else "" + def email(self) -> Email | None: + return self.person.email() if self.person else "" class DocumentAuthorInfo(models.Model): diff --git a/ietf/doc/serializers.py b/ietf/doc/serializers.py index 8767d4ee91..994e814e6c 100644 --- a/ietf/doc/serializers.py +++ b/ietf/doc/serializers.py @@ -21,6 +21,7 @@ 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, @@ -38,7 +39,6 @@ class Meta: "country", "datatracker_person_path", ] - read_only_fields = ["email"] def to_representation(self, instance): """instance -> primitive data types diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index 0578da1b77..0ae7520681 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -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, From c3f0109abde0c092949d84ebc4b6acb28f78f214 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 20 Feb 2026 11:16:19 -0400 Subject: [PATCH 11/15] fix: update RfcAuthorFactory --- ietf/doc/factories.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ietf/doc/factories.py b/ietf/doc/factories.py index aad01be04f..bc38765446 100644 --- a/ietf/doc/factories.py +++ b/ietf/doc/factories.py @@ -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) From c2c780bce415cf59a5d54e31c128ada5e35a7af0 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 20 Feb 2026 12:31:36 -0400 Subject: [PATCH 12/15] fix: consistent blank value in email() --- ietf/doc/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 1ad1d36c74..cc28951be0 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -952,7 +952,7 @@ class Meta: @property def email(self) -> Email | None: - return self.person.email() if self.person else "" + return self.person.email() if self.person else None class DocumentAuthorInfo(models.Model): From 81de5a45502d8fea8fcdeaaf225ac88e68cad639 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 20 Feb 2026 12:35:31 -0400 Subject: [PATCH 13/15] fix: guard against non-prefetched queryset --- ietf/doc/serializers.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/ietf/doc/serializers.py b/ietf/doc/serializers.py index 994e814e6c..d91552ed2e 100644 --- a/ietf/doc/serializers.py +++ b/ietf/doc/serializers.py @@ -15,6 +15,7 @@ GroupSerializer, ) from ietf.name.serializers import StreamNameSerializer +from ietf.utils import log from .models import Document, DocumentAuthor, RfcAuthor @@ -215,7 +216,13 @@ 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() @@ -291,10 +298,20 @@ def get_identifiers(self, doc: Document): @extend_schema_field(RelatedDraftSerializer) def get_draft(self, doc: Document): - try: - related_doc = doc.drafts[0] - except IndexError: - return None + 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 " + f"prefetched draft" + ) + related_doc = doc.came_from_draft() return RelatedDraftSerializer(related_doc).data From 1143c2fbc02a650b37a55b8f0983f94ff611997c Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 20 Feb 2026 12:35:57 -0400 Subject: [PATCH 14/15] test: fix nomcom test --- ietf/nomcom/tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index b6e8c57da7..210788ce07 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -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), From 0dbf6e14b07bc6cede3a898ded13bfbe111a8545 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 20 Feb 2026 15:12:35 -0400 Subject: [PATCH 15/15] refactor: name-addr -> addr for ad/shepherd Also falls back to current primary email for ad/shepherd if the email on record is inactive. --- ietf/doc/serializers.py | 9 ++++----- ietf/group/serializers.py | 12 ++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ietf/doc/serializers.py b/ietf/doc/serializers.py index d91552ed2e..b054b074d7 100644 --- a/ietf/doc/serializers.py +++ b/ietf/doc/serializers.py @@ -180,7 +180,7 @@ def to_representation(self, instance: Document): class ShepherdSerializer(serializers.Serializer): - email = serializers.EmailField(source="formatted_email") + email = serializers.EmailField(source="email_address") class RelatedDraftSerializer(serializers.Serializer): @@ -217,7 +217,7 @@ class RfcFormatSerializer(serializers.Serializer): class RfcMetadataSerializer(serializers.ModelSerializer): """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, ...]. @@ -308,10 +308,9 @@ def get_draft(self, doc: Document): else: # Fallback in case augment_rfc_queryset() was not called log.log( - f"Warning: {self.__class__}.get_draft() called without " - f"prefetched draft" + f"Warning: {self.__class__}.get_draft() called without prefetched draft" ) - related_doc = doc.came_from_draft() + related_doc = doc.came_from_draft() return RelatedDraftSerializer(related_doc).data diff --git a/ietf/group/serializers.py b/ietf/group/serializers.py index 733541d4ab..85f209019c 100644 --- a/ietf/group/serializers.py +++ b/ietf/group/serializers.py @@ -1,9 +1,11 @@ # 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): @@ -18,7 +20,13 @@ class AreaDirectorSerializer(serializers.Serializer): Works with Email or Role """ - email = serializers.EmailField(source="formatted_email") + 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):