@@ -531,21 +531,74 @@ export function backgroundImageUrl(filename: string): string {
531531
532532// Tournament images
533533export async function uploadTournamentImage ( file : File , tournamentId ?: string | number ) : Promise < unknown > {
534- // Backend expects: POST /api/v1/upload/tounament/image?tounament_id={id}
535- // We'll be generous and also include a form field for broader compatibility.
534+ // Try multiple endpoint/param combinations to maximize compatibility
536535 const fd = new FormData ( ) ;
536+ // Match backend exactly: single field named "file"
537537 fd . set ( "file" , file ) ;
538- if ( tournamentId !== undefined ) {
539- // Some backends read form-data, others read query param (with the misspelled key)
540- fd . set ( "tournament_id" , String ( tournamentId ) ) ;
541- }
542538 const token = getAuthToken ( ) ;
543- const url = tournamentId !== undefined
544- ? `${ buildUrl ( API_PATHS . uploadTournamentImage ) } ?tounament_id=${ encodeURIComponent ( String ( tournamentId ) ) } `
545- : buildUrl ( API_PATHS . uploadTournamentImage ) ;
546- const res = await fetch ( url , { method : "POST" , headers : token ? { Authorization : `Bearer ${ token } ` } : undefined , body : fd } ) ;
547- if ( ! res . ok ) throw new Error ( `${ res . status } ${ res . statusText } ` ) ;
548- return await res . json ( ) ;
539+ // Prepare multiple auth header variants to accommodate different backend schemes
540+ const authHeaderVariants : Array < Record < string , string > | undefined > = ( ( ) => {
541+ if ( ! token ) return [ undefined ] ;
542+ return [
543+ { Authorization : `Bearer ${ token } ` } ,
544+ { Authorization : `JWT ${ token } ` } ,
545+ { Authorization : `Token ${ token } ` } ,
546+ { Authorization : token } , // raw token as Authorization value
547+ { "X-Auth-Token" : token } ,
548+ { "X-API-KEY" : token } ,
549+ ] ;
550+ } ) ( ) ;
551+ const idQ = tournamentId !== undefined ? String ( tournamentId ) : undefined ;
552+ const candidates : string [ ] = [ ] ;
553+ // Provided paths (with misspelling)
554+ if ( idQ ) candidates . push ( `${ buildUrl ( API_PATHS . uploadTournamentImage ) } ?tounament_id=${ encodeURIComponent ( idQ ) } ` ) ;
555+ candidates . push ( buildUrl ( API_PATHS . uploadTournamentImage ) ) ;
556+ // Alternate: correct spelling "tournament"
557+ const altBase = buildUrl ( "/api/v1/upload/tournament/image" ) ;
558+ if ( idQ ) {
559+ candidates . push ( `${ altBase } ?tournament_id=${ encodeURIComponent ( idQ ) } ` ) ;
560+ candidates . push ( `${ altBase } ?tounament_id=${ encodeURIComponent ( idQ ) } ` ) ;
561+ }
562+ candidates . push ( altBase ) ;
563+
564+ let lastErr : unknown = null ;
565+ const attempts : Array < { url : string ; status ?: number ; note ?: string ; auth ?: string } > = [ ] ;
566+ for ( const url of candidates ) {
567+ // Try each auth scheme for this URL
568+ for ( const hdr of authHeaderVariants ) {
569+ try {
570+ const headers : Record < string , string > | undefined = hdr ? { ...hdr , accept : "application/json" } : { accept : "application/json" } ;
571+ const res = await fetch ( url , { method : "POST" , headers, body : fd } ) ;
572+ if ( res . ok ) {
573+ try { return await res . json ( ) ; } catch { return null ; }
574+ }
575+ // For 404/405/415, attempt next combination
576+ if ( [ 404 , 405 , 415 ] . includes ( res . status ) ) {
577+ lastErr = new Error ( `${ res . status } ${ res . statusText } ` ) ;
578+ attempts . push ( { url, status : res . status , auth : hdr ? Object . keys ( hdr ) [ 0 ] : "none" } ) ;
579+ // break auth loop if clearly not found; try next URL
580+ break ;
581+ }
582+ const text = await res . text ( ) ;
583+ const msg = text || `${ res . status } ${ res . statusText } ` ;
584+ attempts . push ( { url, status : res . status , note : msg , auth : hdr ? Object . keys ( hdr ) [ 0 ] : "none" } ) ;
585+ // If unauthorized, keep trying other auth variants for the same URL
586+ if ( res . status === 401 || res . status === 403 ) {
587+ continue ; // try next auth header variant for this URL
588+ }
589+ throw new Error ( `Upload failed @ ${ url } → ${ msg } ` ) ;
590+ } catch ( err ) {
591+ lastErr = err as unknown ;
592+ // Continue to next auth header or URL
593+ }
594+ }
595+ }
596+ if ( lastErr ) {
597+ const summary = attempts . map ( a => `${ a . url } [auth:${ a . auth ?? 'none' } ] ${ a . status ?? '' } ${ a . note ?? '' } ` . trim ( ) ) . join ( " | " ) ;
598+ const err = lastErr instanceof Error ? new Error ( `${ lastErr . message } ${ summary ? ` | Tried: ${ summary } ` : '' } ` ) : new Error ( summary || 'Unknown upload error' ) ;
599+ throw err ;
600+ }
601+ throw new Error ( "Upload failed: no valid endpoint" ) ;
549602}
550603export async function listTournamentImageFiles ( tournamentId ?: string ) : Promise < unknown > {
551604 const path = tournamentId
0 commit comments