@@ -89,7 +89,6 @@ async def read_flight(
8989 return await controller .get_flight_by_id (flight_id )
9090
9191
92-
9392@router .put ("/{flight_id}" , status_code = 204 )
9493async def update_flight (
9594 flight_id : str ,
@@ -158,8 +157,80 @@ async def delete_flight(
158157 status_code = 200 ,
159158 response_class = Response ,
160159)
160+ async def get_rocketpy_flight_rpy (
161+ flight_id : str ,
162+ controller : FlightControllerDep ,
163+ ):
164+ """
165+ Export a rocketpy Flight as a portable ``.rpy`` JSON file.
166+
167+ The ``.rpy`` format is architecture-, OS-, and
168+ Python-version-agnostic.
169+
170+ ## Args
171+ ``` flight_id: str ```
172+ """
173+ with tracer .start_as_current_span ("get_rocketpy_flight_rpy" ):
174+ headers = {
175+ 'Content-Disposition' : (
176+ 'attachment; filename=' f'"rocketpy_flight_{ flight_id } .rpy"'
177+ ),
178+ }
179+ rpy = await controller .get_rocketpy_flight_rpy (flight_id )
180+ return Response (
181+ content = rpy ,
182+ headers = headers ,
183+ media_type = "application/json" ,
184+ status_code = 200 ,
185+ )
161186
162- async def get_rocketpy_flight_binary (
187+
188+ @router .post (
189+ "/upload" ,
190+ status_code = 201 ,
191+ responses = {
192+ 201 : {"description" : "Flight imported from .rpy file" },
193+ 413 : {"description" : "Uploaded .rpy file exceeds size limit" },
194+ 422 : {"description" : "Invalid .rpy file" },
195+ },
196+ )
197+ async def import_flight_from_rpy (
198+ file : UploadFile = File (...),
199+ controller : FlightControllerDep = None , # noqa: B008
200+ ) -> FlightImported :
201+ """
202+ Upload a ``.rpy`` JSON file containing a RocketPy Flight.
203+
204+ The file is deserialized and decomposed into its
205+ constituent objects (Environment, Motor, Rocket, Flight).
206+ Each object is persisted as a normal JSON model and the
207+ corresponding IDs are returned. Maximum upload size is 10 MB.
208+
209+ ## Args
210+ ``` file: .rpy JSON upload ```
211+ """
212+ with tracer .start_as_current_span ("import_flight_from_rpy" ):
213+ content = await file .read (MAX_RPY_UPLOAD_BYTES + 1 )
214+ if len (content ) > MAX_RPY_UPLOAD_BYTES :
215+ raise HTTPException (
216+ status_code = status .HTTP_413_REQUEST_ENTITY_TOO_LARGE ,
217+ detail = "Uploaded .rpy file exceeds 10 MB limit." ,
218+ )
219+ return await controller .import_flight_from_rpy (content )
220+
221+
222+ @router .get (
223+ "/{flight_id}/notebook" ,
224+ responses = {
225+ 200 : {
226+ "description" : "Jupyter notebook file download" ,
227+ "content" : {"application/x-ipynb+json" : {}},
228+ }
229+ },
230+ status_code = 200 ,
231+ response_class = Response ,
232+ )
233+ async def get_flight_notebook (
163234 flight_id : str ,
164235 controller : FlightControllerDep ,
165236):
0 commit comments