8000 refactor: reimplement rpcapi in DRF by jennifer-richards · Pull Request #9073 · ietf-tools/datatracker · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

refactor: reimplement rpcapi in DRF #9073

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: feat/rpc-api
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
151 changes: 151 additions & 0 deletions ietf/api/serializers_rpc.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Copyright The IETF Trust 2025, All Rights Reserved
import datetime
< 10000 span class='blob-code-inner blob-code-marker ' data-code-marker="+">from typing import Literal, Optional

from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers

from ietf.doc.models import DocumentAuthor, Document, RelatedDocument
from ietf.person.models import Person


Expand All @@ -11,3 +17,148 @@ class Meta:
model = Person
fields = ["id", "plain_name", "picture"]
read_only_fields = ["id", "plain_name", "picture"]


class EmailPersonSerializer(serializers.Serializer):
email = serializers.EmailField(source="address")
person_pk = serializers.IntegerField(source="person.pk")
name = serializers.CharField(source="person.name")
last_name = serializers.CharField(source="person.last_name")
initials = serializers.CharField(source="person.initials")


class LowerCaseEmailField(serializers.EmailField):
def to_representation(self, value):
return super().to_representation(value).lower()


class AuthorPersonSerializer(serializers.ModelSerializer):
person_pk = serializers.IntegerField(source="pk", read_only=True)
last_name = serializers.CharField()
initials = serializers.CharField()
email_addresses = serializers.ListField(
source="email_set.all", child=LowerCaseEmailField()
)

class Meta:
model = Person
fields = ["person_pk", "name", "last_name", "initials", "email_addresses"]


class RfcWithAuthorsSerializer(serializers.ModelSerializer):
authors = AuthorPersonSerializer(many=True)

class Meta:
model = Document
fields = ["rfc_number", "authors"]


class DraftWithAuthorsSerializer(serializers.ModelSerializer):
draft_name = serializers.CharField(source="name")
authors = AuthorPersonSerializer(many=True)

class Meta:
model = Document
fields = ["draft_name", "authors"]


class DocumentAuthorSerializer(serializers.ModelSerializer):
"""Serializer for a Person in a response"""

plain_name = serializers.SerializerMethodField()

class Meta:
model = DocumentAuthor
fields = ["person", "plain_name"]

def get_plain_name(self, document_author: DocumentAuthor) -> str:
return document_author.person.plain_name()


class FullDraftSerializer(serializers.ModelSerializer):
source_format = serializers.SerializerMethodField()
authors = DocumentAuthorSerializer(many=True, source="documentauthor_set")
shepherd = serializers.SerializerMethodField()

class Meta:
model = Document
fields = [
"id",
"name",
"rev",
"stream",
"title",
"pages",
"source_format",
"authors",
"shepherd",
"intended_std_level",
]

def get_source_format(
self, doc: Document
) -> Literal["unknown", "xml-v2", "xml-v3", "txt"]:
submission = doc.submission()
if submission is None:
return "unknown"
if ".xml" in submission.file_types:
if submission.xml_version == "3":
return "xml-v3"
else:
return "xml-v2"
elif ".txt" in submission.file_types:
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:
model = Document
fields = [
"id",
"name",
"rev",
"stream",
"title",
"pages",
"source_format",
"authors",
]


class SubmittedToQueueSerializer(FullDraftSerializer):
submitted = serializers.SerializerMethodField()

class Meta:
model = Document
fields = [
"id",
"name",
"stream",
"submitted",
]

def get_submitted(self, doc) -> Optional[datetime.datetime]:
event = doc.sent_to_rfc_editor_event()
return None if event is None else event.time


class OriginalStreamSerializer(serializers.ModelSerializer):
stream = serializers.CharField(read_only=True, source="orig_stream_id")

class Meta:
model = Document
fields = ["rfc_number", "stream"]


class ReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = Document
fields = ["id", "name"]
read_only_fields = ["id", "name"]
2 changes: 1 addition & 1 deletion ietf/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
url(r'^v2/person/person', api_views.ApiV2PersonExportView.as_view()),
# --- DRF API ---
# path("core/", include(core_router.urls)),
path("purple/", include("ietf.api.urls_rpc")),
path("red/", include(red_router.urls)),
path("schema/", SpectacularAPIView.as_view()),
#
Expand Down Expand Up @@ -97,7 +98,6 @@
url(r'^rfcdiff-latest-json/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', api_views.rfcdiff_latest_json),
# direct authentication
url(r'^directauth/?$', api_views.directauth),
url(r'^rpc/', include('ietf.api.urls_rpc')),
]

# Additional (standard) Tastypie endpoints
Expand Down
43 changes: 23 additions & 20 deletions ietf/api/urls_rpc.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
# Copyright The IETF Trust 2023-2024, All Rights Reserved
# Copyright The IETF Trust 2023-2025, All Rights Reserved

from rest_framework import routers

from django.conf import settings
from django.urls import include, path

from ietf.api import views_rpc, views_rpc_demo
from ietf.utils.urls import url

router = routers.DefaultRouter()
router.register(r"draft", views_rpc.DraftViewSet, basename="draft")
router.register(r"person", views_rpc.PersonViewSet)
router.register(r"rfc", views_rpc.RfcViewSet, basename="rfc")

if settings.SERVER_MODE not in {"production", "test"}:
# for non production demos
router.register(r"demo", views_rpc_demo.DemoViewSet, basename="demo")


urlpatterns = [
url(r"^doc/drafts/(?P<doc_id>[0-9]+)/$", views_rpc.rpc_draft),
url(r"^doc/drafts/(?P<doc_id>[0-9]+)/references/$", views_rpc.rpc_draft_refs),
url(r"^doc/drafts_by_names/$", views_rpc.drafts_by_names),
url(r"^doc/submitted_to_rpc/$", views_rpc.submitted_to_rpc),
url(r"^doc/rfc/original_stream/$", views_rpc.rfc_original_stream),
url(r"^doc/rfc/authors/$", views_rpc.rfc_authors),
url(r"^doc/draft/authors/$", views_rpc.draft_authors),
url(r"^person/persons_by_email/$", views_rpc.persons_by_email),
url(r"^person/(?P<person_id>[0-9]+)/$", views_rpc.rpc_person),
url(r"^persons/$", views_rpc.rpc_persons),
url(r"^doc/drafts_by_names/", views_rpc.DraftsByNamesView.as_view()),
url(r"^persons/search/", views_rpc.RpcPersonSearch.as_view()),
url(r"^subject/(?P<subject_id>[0-9]+)/person/$", views_rpc.rpc_subject_person),
path(r"subject/<str:subject_id>/person/", views_rpc.SubjectPersonView.as_view()),
]

if settings.SERVER_MODE not in {"production", "test"}:
# for non production demos
urlpatterns.append(
url(r"^doc/create_demo_draft/$", views_rpc_demo.create_demo_draft)
)
urlpatterns.append(
url(r"^person/create_demo_person/$", views_rpc_demo.create_demo_person)
)
# add routers at the end so individual routes can steal parts of their address
# space (specifically, ^person/ routes so far)
urlpatterns.extend(
[
path("", include(router.urls)),
]
)
Loading
0