3636_admin_attempts : dict [str , dict ] = {}
3737
3838
39+ def _flash_html (message : str | None , level : str = "info" , reason : str | None = None ) -> str :
40+ if not message :
41+ return ""
42+ safe_level = level if level in {"success" , "error" , "warning" , "info" } else "info"
43+ allowed_reasons = {"auth" , "general" , "success" }
44+ reason_attr = f" data-flash-reason='{ reason } '" if reason in allowed_reasons else ""
45+ return (
46+ f"<div class='flash flash--{ safe_level } ' data-flash-level='{ safe_level } '{ reason_attr } role='alert'>"
47+ f"{ html .escape (message )} "
48+ "</div>"
49+ )
50+
51+
3952async def enforce_rate_limit (request : Request ):
4053 client = request .client .host if request .client else "unknown"
4154 allowed , retry_after = rate_limiter .hit (client )
@@ -113,17 +126,19 @@ def _human_bytes(value: int) -> str:
113126 return "0 B"
114127
115128
116- def _render_admin_login (message : str | None = None ) -> str :
117- flash_html = f"<div class='flash'> { html . escape (message ) } </div>" if message else ""
129+ def _render_admin_login (message : str | None = None , level : str = "info" , reason : str | None = None ) -> str :
130+ flash_html = _flash_html (message , level , reason )
118131 return render_template ("pages/admin_login.html" , {"flash_message" : flash_html })
119132
120133
121- def _render_admin_page (session : Session , message : str | None = None ) -> str :
134+ def _render_admin_page (
135+ session : Session , message : str | None = None , level : str = "info" , reason : str | None = None
136+ ) -> str :
122137 totals = fetch_storage_totals (session )
123138 snapshot = metrics .snapshot ()
124139 stmt = select (FileModel ).order_by (FileModel .created_at .desc ()).limit (50 )
125140 files = session .exec (stmt ).all ()
126- flash_html = f"<div class='flash'> { html . escape (message ) } </div>" if message else ""
141+ flash_html = _flash_html (message , level , reason )
127142 return render_template (
128143 "pages/admin.html" ,
129144 {
@@ -197,13 +212,6 @@ async def _auth_admin(request: Request, allow_blank: bool):
197212 raise HTTPException (status_code = 401 , detail = msg )
198213
199214
200- async def require_admin (request : Request ) -> str :
201- success , _ , _ = await _auth_admin (request , allow_blank = False )
202- if success :
203- return ADMIN_PASSWORD
204- raise HTTPException (status_code = 500 , detail = "Admin authentication failed" )
205-
206-
207215def _remove_file_from_disk (stored_name : str ) -> None :
208216 try :
209217 path = (UPLOAD_ROOT / stored_name ).resolve ()
@@ -219,7 +227,7 @@ async def admin_dashboard(request: Request, session: Session = Depends(get_sessi
219227 if success :
220228 html = _render_admin_page (session , message )
221229 return HTMLResponse (content = html )
222- html = _render_admin_login (message )
230+ html = _render_admin_login (message , "error" if message else "info" , "auth" if message else None )
223231 status = 429 if locked and message else 200
224232 return HTMLResponse (content = html , status_code = status )
225233
@@ -228,38 +236,59 @@ async def admin_dashboard(request: Request, session: Session = Depends(get_sessi
228236async def admin_delete_file (
229237 request : Request ,
230238 session : Session = Depends (get_session ),
231- _ : str = Depends (require_admin ),
232239):
233- form = getattr (request .state , "admin_form" , None ) or await request .form ()
240+ form = getattr (request .state , "admin_form" , None )
241+ if form is None :
242+ form = await request .form ()
243+ request .state .admin_form = form
244+
245+ success , message , locked = await _auth_admin (request , allow_blank = True )
246+ if not success :
247+ status = 429 if locked else 401
248+ failure_message = message or "Admin password required."
249+ html = _render_admin_page (session , failure_message , "error" , "auth" )
250+ return HTMLResponse (content = html , status_code = status )
251+
234252 file_id = form .get ("file_id" )
235253 if not file_id :
236254 raise HTTPException (status_code = 400 , detail = "Missing file_id" )
237255 file = session .get (FileModel , file_id )
238256 if not file :
239- html = _render_admin_page (session , "File not found." )
257+ html = _render_admin_page (session , "File not found." , "error" , "general" )
240258 return HTMLResponse (content = html , status_code = 404 )
241259
242260 _remove_file_from_disk (file .stored_name )
243261 session .delete (file )
244262 session .commit ()
245- html = _render_admin_page (session , "File deleted." )
263+ html = _render_admin_page (session , "File deleted." , "success" , "success" )
246264 return HTMLResponse (content = html )
247265
248266
249267@router .post ("/admin/delete-all" , response_class = HTMLResponse )
250268async def admin_delete_all (
251269 request : Request ,
252270 session : Session = Depends (get_session ),
253- _ : str = Depends (require_admin ),
254271):
272+ form = getattr (request .state , "admin_form" , None )
273+ if form is None :
274+ form = await request .form ()
275+ request .state .admin_form = form
276+
277+ success , message , locked = await _auth_admin (request , allow_blank = True )
278+ if not success :
279+ status = 429 if locked else 401
280+ failure_message = message or "Admin password required."
281+ html = _render_admin_page (session , failure_message , "error" , "auth" )
282+ return HTMLResponse (content = html , status_code = status )
283+
255284 files = session .exec (select (FileModel )).all ()
256285 deleted = 0
257286 for file in files :
258287 _remove_file_from_disk (file .stored_name )
259288 session .delete (file )
260289 deleted += 1
261290 session .commit ()
262- html = _render_admin_page (session , f"Deleted { deleted } files." )
291+ html = _render_admin_page (session , f"Deleted { deleted } files." , "success" , "success" )
263292 return HTMLResponse (content = html )
264293
265294
0 commit comments