88from django .utils import timezone
99from drf_spectacular .types import OpenApiTypes
1010from drf_spectacular .utils import extend_schema_field
11- from rest_framework import serializers
11+ from rest_framework import fields , serializers
1212
1313from ietf .doc .expire import move_draft_files_to_archive
1414from ietf .doc .models import (
@@ -265,6 +265,23 @@ def __init__(self, **kwargs):
265265 super ().__init__ (regex , ** kwargs )
266266
267267
268+ class RfcGroupRelatedField (serializers .SlugRelatedField ):
269+ """SlugRelatedField that translates None / "" to the acronym "none" """
270+
271+ def __init__ (self , ** kwargs ):
272+ super ().__init__ (
273+ slug_field = "acronym" ,
274+ queryset = Group .objects .all (),
275+ allow_null = True ,
276+ required = False ,
277+ )
278+
279+ def run_validation (self , data = fields .empty ):
280+ # Use the Group with acronym "none" when group is not specified
281+ if data is fields .empty or data is None or data == "" :
282+ data = "none"
283+ return super ().run_validation (data )
284+
268285
269286class RfcPubSerializer (serializers .ModelSerializer ):
270287 """Write-only serializer for RFC publication"""
@@ -279,9 +296,7 @@ class RfcPubSerializer(serializers.ModelSerializer):
279296
280297 # fields on the RFC Document that need tweaking from ModelSerializer defaults
281298 rfc_number = serializers .IntegerField (min_value = 1 , required = True )
282- group = serializers .SlugRelatedField (
283- slug_field = "acronym" , queryset = Group .objects .all (), required = False
284- )
299+ group = RfcGroupRelatedField ()
285300 stream = serializers .PrimaryKeyRelatedField (
286301 queryset = StreamName .objects .filter (used = True )
287302 )
@@ -556,6 +571,18 @@ class EditableRfcSerializer(serializers.ModelSerializer):
556571 child = SubseriesNameField (required = False ),
557572 write_only = True ,
558573 )
574+ updates = serializers .ListField (
575+ child = serializers .IntegerField (),
576+ required = False ,
577+ write_only = True ,
578+ help_text = "List of RFC numbers this document updates."
579+ )
580+ obsoletes = serializers .ListField (
581+ child = serializers .IntegerField (),
582+ required = False ,
583+ write_only = True ,
584+ help_text = "List of RFC numbers this document obsoletes."
585+ )
559586
560587 class Meta :
561588 model = Document
@@ -569,7 +596,27 @@ class Meta:
569596 "std_level" ,
570597 "subseries" ,
571598 "keywords" ,
599+ "updates" ,
600+ "obsoletes" ,
601+ ]
602+
603+ def _validate_rfc_number_list (self , field_name , rfc_numbers ):
604+ """Raise ValidationError if any RFC numbers in the list don't exist."""
605+ unknown = [
606+ n for n in rfc_numbers
607+ if not Document .objects .filter (rfc_number = n , type_id = "rfc" ).exists ()
572608 ]
609+ if unknown :
610+ raise serializers .ValidationError (
611+ {field_name : [f"Unknown RFC number: { n } " for n in unknown ]}
612+ )
613+ return rfc_numbers
614+
615+ def validate_updates (self , value ):
616+ return self ._validate_rfc_number_list ("updates" , value )
617+
618+ def validate_obsoletes (self , value ):
619+ return self ._validate_rfc_number_list ("obsoletes" , value )
573620
574621 def create (self , validated_data ):
575622 raise RuntimeError ("Cannot create with this serializer" )
@@ -587,6 +634,8 @@ def update(self, instance, validated_data):
587634 published = validated_data .pop ("published" , omitted )
588635 subseries = validated_data .pop ("subseries" , omitted )
589636 authors_data = validated_data .pop ("rfcauthor_set" , omitted )
637+ updates = validated_data .pop ("updates" , omitted )
638+ obsoletes = validated_data .pop ("obsoletes" , omitted )
590639
591640 # Transaction to clean up if something fails
592641 with transaction .atomic ():
@@ -658,6 +707,24 @@ def update(self, instance, validated_data):
658707 )
659708 )
660709 )
710+ if updates is not omitted :
711+ RelatedDocument .objects .filter (
712+ source = rfc , relationship_id = "updates"
713+ ).exclude (target__rfc_number__in = updates ).delete ()
714+ for rfc_num in updates :
715+ target = Document .objects .get (rfc_number = rfc_num , type_id = "rfc" )
716+ RelatedDocument .objects .get_or_create (
717+ source = rfc , relationship_id = "updates" , target = target
718+ )
719+ if obsoletes is not omitted :
720+ RelatedDocument .objects .filter (
721+ source = rfc , relationship_id = "obs"
722+ ).exclude (target__rfc_number__in = obsoletes ).delete ()
723+ for rfc_num in obsoletes :
724+ target = Document .objects .get (rfc_number = rfc_num , type_id = "rfc" )
725+ RelatedDocument .objects .get_or_create (
726+ source = rfc , relationship_id = "obs" , target = target
727+ )
661728
662729 # update subseries relations
663730 if subseries is not omitted :
0 commit comments