@@ -82,14 +82,20 @@ def _find_action(self, param_keys, separator) -> UpdateAction:
8282 # Check URL parameters
8383 for param_key in param_keys :
8484 try :
85- params = {
86- param .strip ()
87- for param in self .request .query_params [param_key ].split ("," )
88- if separator in param or param .strip () in ("" , "preserve" )
89- }
85+ params = set (
86+ filter (
87+ lambda param : separator in param or param in ("" , "preserve" ),
88+ map (str .strip , self .request .query_params [param_key ].split ("," )),
89+ )
90+ )
9091 except KeyError :
9192 continue
92- if len (params ) > 1 :
93+ if not params :
94+ continue
95+
96+ try :
97+ (param ,) = params # unpacks if params has exactly one element
98+ except ValueError : # more than one element
9399 if params & {"" , "preserve" }:
94100 raise ValidationError (
95101 detail = f'IP parameter "{ param_key } " cannot have addresses and "preserve" at the same time.' ,
@@ -100,23 +106,23 @@ def _find_action(self, param_keys, separator) -> UpdateAction:
100106 detail = f'IP parameter "{ param_key } " cannot use subnet notation with multiple addresses.' ,
101107 code = "multiple-subnet" ,
102108 )
103- if params :
104- params = list ( params )
105- if len ( params ) == 1 and "/" in params [ 0 ] :
106- try :
107- subnet = ip_network ( params [ 0 ], strict = False )
108- return UpdateWithSubnet ( subnet = subnet )
109- except ValueError as e :
110- raise ValidationError (
111- detail = f'IP parameter " { param_key } " is an invalid subnet: { e } ' ,
112- code = "invalid- subnet" ,
113- )
114- if params == [ "preserve" ]:
115- return PreserveIPs ()
116- elif params == [ "" ]:
117- return SetIPs ( ips = [] )
118- else :
119- return SetIPs (ips = params )
109+ else : # one element
110+ match param :
111+ case "" :
112+ return SetIPs ( ips = [])
113+ case "preserve" :
114+ return PreserveIPs ( )
115+ case str ( x ) if "/" in x :
116+ try :
117+ subnet = ip_network ( param , strict = False )
118+ return UpdateWithSubnet ( subnet = subnet )
119+ except ValueError as e :
120+ raise ValidationError (
121+ detail = f'IP parameter " { param_key } " is an invalid subnet: { e } ' ,
122+ code = "invalid-subnet" ,
123+ )
124+
125+ return SetIPs (ips = list ( params ) )
120126
121127 # Check remote IP address
122128 client_ip = self .request .META .get ("REMOTE_ADDR" )
@@ -184,9 +190,15 @@ def qnames(self) -> set[str]:
184190
185191 @cached_property
186192 def domain (self ) -> Domain :
187- domains = Domain .objects .filter_qnames (
188- self .qnames , owner = self .request .user
189- ).all ()
193+ qname_qs = (
194+ Domain .objects .filter_qname (qname , owner = self .request .user )
195+ for qname in self .qnames
196+ )
197+ domains = (
198+ Domain .objects .none ()
199+ .union (* (qs .order_by ("-name_length" )[:1 ] for qs in qname_qs ), all = True )
200+ .all ()
201+ )
190202
191203 if len (domains ) != len (self .qnames ):
192204 metrics .get ("desecapi_dynDNS12_domain_not_found" ).inc ()
@@ -224,52 +236,46 @@ def _get_records(records: list[RR], action: UpdateAction) -> list[str] | None:
224236 Determines the final list of IP address records based on the given action.
225237
226238 Args:
227- records (list): A list of Record objects for a single domain .
239+ records (list): A list of RR objects ( for one RRset) .
228240 action (UpdateAction): The action to perform.
229241
230242 Returns:
231243 list or None: A list of IP address strings, or None if the records should be preserved.
232244 """
233- if isinstance (action , SetIPs ):
234- return action .ips
235- elif isinstance (action , UpdateWithSubnet ):
236- return replace_ip_subnet (records , action .subnet )
237- elif isinstance (action , PreserveIPs ):
238- return None
245+ match action :
246+ case SetIPs ():
247+ return action .ips
248+ case UpdateWithSubnet ():
249+ return replace_ip_subnet (records , action .subnet )
250+ case PreserveIPs ():
251+ return None
239252
240253 def get (self , request , * args , ** kwargs ) -> Response :
241- instances = self .get_queryset (). all ()
254+ instances = self .get_queryset ()
242255
243- grouped_records = defaultdict (list )
256+ subname_records = defaultdict (list )
244257 for rrset in instances :
245- grouped_records [rrset .subname ].extend (rrset .records .all ())
258+ subname_records [rrset .subname ].extend (rrset .records .all ())
246259
247260 actions = {
248261 "A" : self ._find_action (["myip" , "myipv4" , "ip" ], separator = "." ),
249262 "AAAA" : self ._find_action (["myipv6" , "ipv6" , "myip" , "ip" ], separator = ":" ),
250263 }
251264
252- data = []
253- for subname in self .subnames :
254- subname_records = grouped_records .get (subname , [])
255-
256- data += [
257- {
258- "type" : type_ ,
259- "subname" : subname ,
260- "ttl" : 60 ,
261- "records" : records ,
262- }
263- for type_ , action in actions .items ()
264- if (records := self ._get_records (subname_records , action )) is not None
265- ]
266-
267- serializer = self .get_serializer (
268- instances ,
269- data = data ,
270- many = True ,
271- partial = True ,
272- )
265+ data = [
266+ {
267+ "type" : type_ ,
268+ "subname" : subname ,
269+ "ttl" : 60 ,
270+ "records" : records ,
271+ }
272+ for subname in self .subnames
273+ for type_ , action in actions .items ()
274+ if (records := self ._get_records (subname_records [subname ], action ))
275+ is not None
276+ ]
277+
278+ serializer = self .get_serializer (instances , data = data , many = True , partial = True )
273279 try :
274280 serializer .is_valid (raise_exception = True )
275281 except ValidationError as e :
0 commit comments