1010from fastapi import (
1111 APIRouter ,
1212 BackgroundTasks ,
13+ Body ,
1314 Depends ,
1415 HTTPException ,
1516 Query ,
1920 status ,
2021)
2122from fastapi .dependencies .models import Dependant
22- from pydantic import parse_obj_as
23+ from pydantic import TypeAdapter
2324from pydantic .types import Json
2425from typing_extensions import Annotated
2526
@@ -98,14 +99,17 @@ def _enrich_statement_with_authority(
9899) -> None :
99100 # authority: Information about whom or what has asserted the statement is true.
100101 # https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#249-authority
101- statement ["authority" ] = current_user .agent
102+ statement ["authority" ] = current_user .agent .model_dump (
103+ exclude_none = True , mode = "json"
104+ )
102105
103106
104107def _parse_agent_parameters (agent_obj : dict ) -> AgentParameters :
105108 """Parse a dict and return an AgentParameters object to use in queries."""
106109 # Transform agent to `dict` as FastAPI cannot parse JSON (seen as string)
107110
108- agent = parse_obj_as (BaseXapiAgent , agent_obj )
111+ adapter = TypeAdapter (BaseXapiAgent )
112+ agent = adapter .validate_python (agent_obj )
109113
110114 agent_query_params = {}
111115 if isinstance (agent , BaseXapiAgentWithMbox ):
@@ -119,7 +123,7 @@ def _parse_agent_parameters(agent_obj: dict) -> AgentParameters:
119123 agent_query_params ["account__home_page" ] = agent .account .homePage
120124
121125 # Overwrite `agent` field
122- return AgentParameters .construct (** agent_query_params )
126+ return AgentParameters .model_construct (** agent_query_params )
123127
124128
125129def strict_query_params (request : Request ) -> None :
@@ -141,7 +145,7 @@ def strict_query_params(request: Request) -> None:
141145
142146@router .get ("" )
143147@router .get ("/" )
144- async def get ( # noqa: PLR0913
148+ async def get ( # noqa: PLR0912, PLR0913
145149 request : Request ,
146150 current_user : Annotated [
147151 AuthenticatedUser ,
@@ -169,7 +173,7 @@ async def get( # noqa: PLR0913
169173 None ,
170174 description = "Filter, only return Statements matching the specified Verb id" ,
171175 ),
172- activity : Optional [IRI ] = Query (
176+ activity : Optional [Annotated [ IRI , Body ()] ] = Query (
173177 None ,
174178 description = (
175179 "Filter, only return Statements for which the Object "
@@ -334,7 +338,14 @@ async def get( # noqa: PLR0913
334338 # Overwrite `agent` field
335339 query_params ["agent" ] = _parse_agent_parameters (
336340 json .loads (query_params ["agent" ])
337- )
341+ ).model_dump (mode = "json" , exclude_none = True )
342+
343+ # Coerce `verb` and `activity` as IRI
344+ if query_params .get ("verb" ):
345+ query_params ["verb" ] = IRI (query_params ["verb" ])
346+
347+ if query_params .get ("activity" ):
348+ query_params ["activity" ] = IRI (query_params ["activity" ])
338349
339350 # mine: If using scopes, only restrict users with limited scopes
340351 if settings .LRS_RESTRICT_BY_SCOPES :
@@ -346,7 +357,9 @@ async def get( # noqa: PLR0913
346357
347358 # Filter by authority if using `mine`
348359 if mine :
349- query_params ["authority" ] = _parse_agent_parameters (current_user .agent )
360+ query_params ["authority" ] = _parse_agent_parameters (
361+ current_user .agent .model_dump (mode = "json" )
362+ ).model_dump (mode = "json" , exclude_none = True )
350363
351364 if "mine" in query_params :
352365 query_params .pop ("mine" )
@@ -355,7 +368,7 @@ async def get( # noqa: PLR0913
355368 try :
356369 query_result = await await_if_coroutine (
357370 BACKEND_CLIENT .query_statements (
358- RalphStatementsQuery .construct (** {** query_params , "limit" : limit })
371+ RalphStatementsQuery .model_construct (** {** query_params , "limit" : limit })
359372 )
360373 )
361374 except BackendException as error :
@@ -415,7 +428,7 @@ async def put(
415428 LRS Specification:
416429 https://github.com/adlnet/xAPI-Spec/blob/1.0.3/xAPI-Communication.md#211-put-statements
417430 """
418- statement_as_dict = statement .dict (exclude_unset = True )
431+ statement_as_dict = statement .model_dump (exclude_unset = True , mode = "json" )
419432 statement_id = str (statement_id )
420433
421434 statement_as_dict .update (id = str (statement_as_dict .get ("id" , statement_id )))
@@ -504,7 +517,9 @@ async def post( # noqa: PLR0912
504517
505518 # Enrich statements before forwarding
506519 statements_dict = {}
507- for statement in (x .dict (exclude_unset = True ) for x in statements ):
520+ for statement in (
521+ x .model_dump (exclude_unset = True , mode = "json" ) for x in statements
522+ ):
508523 _enrich_statement_with_id (statement )
509524 # Requests with duplicate statement IDs are considered invalid
510525 if statement ["id" ] in statements_dict :
0 commit comments