66import os
77from typing import Any
88
9- from minio import Minio
10- from starlette .datastructures import UploadFile as StarletteUploadFile
11-
129import starlette .requests
13- from fastapi import APIRouter , Depends , File , HTTPException , UploadFile
14-
1510from api .database import (
1611 get_async_session ,
1712 get_engine ,
2419 storage_object_soft_delete ,
2520)
2621from api .routes .security import has_access
22+ from fastapi import APIRouter , Depends , File , HTTPException , UploadFile
23+ from minio import Minio
24+ from starlette .datastructures import UploadFile as StarletteUploadFile
2725
2826router = APIRouter (
2927 prefix = "/object" ,
@@ -37,7 +35,9 @@ def guess_mime_type(filename: str) -> str:
3735 return mime or "application/octet-stream"
3836
3937
40- def sha256_of_uploadfile (upload : StarletteUploadFile , chunk_size : int = 1024 * 1024 ) -> str :
38+ def sha256_of_uploadfile (
39+ upload : StarletteUploadFile , chunk_size : int = 1024 * 1024
40+ ) -> str :
4141 """
4242 Compute sha256 while reading the upload stream.
4343 IMPORTANT: resets file pointer back to 0 afterwards so MinIO upload works.
@@ -70,7 +70,9 @@ def get_storage_host_bucket() -> tuple[str, str]:
7070 import urllib .parse
7171
7272 raw_host = os .environ ["storage_host" ]
73- parsed = urllib .parse .urlparse (raw_host if "://" in raw_host else f"https://{ raw_host } " )
73+ parsed = urllib .parse .urlparse (
74+ raw_host if "://" in raw_host else f"https://{ raw_host } "
75+ )
7476 host = parsed .hostname or raw_host .split (":" )[0 ]
7577 bucket = os .environ ["maps_bucket_name" ]
7678 return host , bucket
@@ -107,7 +109,9 @@ async def get_object(id: int):
107109 async with async_session () as session :
108110 row = await storage_object_get_by_id (session , id = id )
109111 if row is None :
110- raise HTTPException (status_code = 404 , detail = f"Object with id ({ id } ) not found" )
112+ raise HTTPException (
113+ status_code = 404 , detail = f"Object with id ({ id } ) not found"
114+ )
111115 return row
112116
113117
@@ -124,15 +128,19 @@ async def create_object(
124128 - Uses DB to prevent duplicates (same host/bucket/key).
125129 """
126130 if not user_has_access :
127- raise HTTPException (status_code = 403 , detail = "User does not have access to create object" )
131+ raise HTTPException (
132+ status_code = 403 , detail = "User does not have access to create object"
133+ )
128134
129135 if "multipart/form-data" not in (request .headers .get ("content-type" ) or "" ):
130136 raise HTTPException (status_code = 400 , detail = "Expected multipart/form-data" )
131137
132138 form = await request .form ()
133139 uploads = form .getlist ("object" )
134140 if not uploads :
135- raise HTTPException (status_code = 400 , detail = "No files provided under field name 'object'" )
141+ raise HTTPException (
142+ status_code = 400 , detail = "No files provided under field name 'object'"
143+ )
136144
137145 host , bucket = get_storage_host_bucket ()
138146 minio_client = get_minio_client ()
@@ -171,7 +179,9 @@ async def create_object(
171179 metadata = {"sha256" : sha256 },
172180 )
173181 except Exception as e :
174- raise HTTPException (status_code = 500 , detail = f"Failed to upload to S3: { e } " )
182+ raise HTTPException (
183+ status_code = 500 , detail = f"Failed to upload to S3: { e } "
184+ )
175185
176186 row = await storage_object_insert (
177187 session ,
@@ -183,7 +193,9 @@ async def create_object(
183193 source = json .dumps ({}),
184194 )
185195 if row is None :
186- raise HTTPException (status_code = 500 , detail = "Failed to insert storage.object record" )
196+ raise HTTPException (
197+ status_code = 500 , detail = "Failed to insert storage.object record"
198+ )
187199
188200 created .append (row )
189201
@@ -203,7 +215,9 @@ async def patch_object(
203215 Supported keys: key, mime_type, source
204216 """
205217 if not user_has_access :
206- raise HTTPException (status_code = 403 , detail = "User does not have access to update object" )
218+ raise HTTPException (
219+ status_code = 403 , detail = "User does not have access to update object"
220+ )
207221
208222 key = body .get ("key" )
209223 mime_type = body .get ("mime_type" )
@@ -223,7 +237,9 @@ async def patch_object(
223237 source = source ,
224238 )
225239 if row is None :
226- raise HTTPException (status_code = 404 , detail = f"Object with id ({ id } ) not found" )
240+ raise HTTPException (
241+ status_code = 404 , detail = f"Object with id ({ id } ) not found"
242+ )
227243
228244 await session .commit ()
229245 return row
@@ -241,7 +257,9 @@ async def delete_object(
241257 - hard=False: soft delete (sets deleted_on) and keeps object in MinIO
242258 """
243259 if not user_has_access :
244- raise HTTPException (status_code = 403 , detail = "User does not have access to delete object" )
260+ raise HTTPException (
261+ status_code = 403 , detail = "User does not have access to delete object"
262+ )
245263
246264 minio_client = get_minio_client ()
247265
@@ -251,7 +269,9 @@ async def delete_object(
251269 async with async_session () as session :
252270 obj = await storage_object_get_by_id (session , id = id )
253271 if obj is None :
254- raise HTTPException (status_code = 404 , detail = f"Object with id ({ id } ) not found" )
272+ raise HTTPException (
273+ status_code = 404 , detail = f"Object with id ({ id } ) not found"
274+ )
255275
256276 object_key = obj .get ("key" )
257277 object_bucket = obj .get ("bucket" )
@@ -268,14 +288,18 @@ async def delete_object(
268288
269289 deleted_id = await storage_object_hard_delete (session , id = id )
270290 if deleted_id is None :
271- raise HTTPException (status_code = 500 , detail = "Failed to delete DB record" )
291+ raise HTTPException (
292+ status_code = 500 , detail = "Failed to delete DB record"
293+ )
272294
273295 await session .commit ()
274296 return {"status" : "deleted" , "id" : id , "hard" : True }
275297
276298 row = await storage_object_soft_delete (session , id = id )
277299 if row is None :
278- raise HTTPException (status_code = 500 , detail = "Failed to soft-delete DB record" )
300+ raise HTTPException (
301+ status_code = 500 , detail = "Failed to soft-delete DB record"
302+ )
279303
280304 await session .commit ()
281305 return {"status" : "deleted" , "hard" : False , "object" : row }
0 commit comments