Catalog/docs/api-race-upload-spec.md
MaddoScientisto 15b1da4371 feat: Add race upload functionality and file transfer endpoints
- Implemented IRaceUploadCommunicationClient with methods for saving races, creating race points, indexing race points, retrieving race details, and uploading files to the receiver.
- Added ReceiveFilePath option to CatalogCommunicationOptions for file transfer configuration.
- Enhanced CatalogCommunicationServiceCollectionExtensions to validate ReceiveFilePath.
- Developed RaceUploadCommunicationClient to handle race-related API interactions, including saving race data and uploading processed images.
- Updated API documentation to reflect new race upload and file transfer endpoints.
- Modified Avalonia UI to support race creation and processed image uploads, including new input fields and buttons.
- Introduced RaceSaveRequest and ReceiveFileUploadRequest models for structured data handling.
2026-02-28 16:54:08 +01:00

8.2 KiB

API Specification (code-backed): races, images, and authentication

Scope and evidence

This document is reverse-engineered from:

  • JSP/JS usage in the web app
  • WEB-INF/web.xml servlet mappings
  • decompiled sources in WEB-INF/lib/*_src (notably AblServletSvlt, AcServlet, GaraSvlt, Logon4Svlt, Menu4Svlt, GetFileTnSvlt)

The upload response schemas below are now confirmed from code, not inferred.

Base URL

Examples use:

  • https://your-host

Authentication (how to obtain the usable token)

Actual auth model

This app uses server session authentication, not JWT bearer tokens.

Login success sets session attributes:

  • loginUser_id (Long)
  • utenteLogon (user object)

For automation, the practical token is the session cookie (JSESSIONID and any app cookies).

Admin login endpoint

  • POST /admin/menu/Menu4.abl
  • Servlet mapping: com.ablia.anag.servlet.Menu4Svlt (extends Logon4Svlt)
  • Body (application/x-www-form-urlencoded):
    • login
    • pwd
    • cmdIU=check

Other cmdIU values used:

  • cmdIU=login (logout)
  • cmdIU=np (password change)
  • cmdIU=checkSso (SSO branch if enabled)
curl -i -c cookies.txt -X POST "https://your-host/admin/menu/Menu4.abl" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data "login=YOUR_USER&pwd=YOUR_PASSWORD&cmdIU=check"

Reuse cookie jar for authenticated calls:

curl -i -b cookies.txt "https://your-host/admin/pg/Gara.abl?cmd=search"

Token note (Bearer/Basic)

  • No Authorization: Bearer ... flow is present in inspected sources.
  • A helper exists to parse Authorization: Basic (getBasicAuthorizationHeaders), but no race/photo endpoint uses it directly.

Relevant endpoints

Admin race/photo endpoints

  • POST|GET /admin/pg/Gara.abl
  • POST|GET /admin/pg/Foto.abl
  • POST|GET /admin/pg/TipoGara.abl
  • POST|GET /admin/pg/LogFoto.abl

Deployment caveat:

  • some deployments expose the same admin pages under POST|GET /admin/pg_RUS/*.abl.
  • On https://www.regalamiunsorriso.it, post-login dashboard links point to /admin/pg_RUS/Gara.abl (not /admin/pg/Gara.abl).
  • POST|GET /Foto2.abl
  • POST|GET /Logon.abl (mapped to com.ablia.pg.servlet.Logon2Svlt)
  • POST|GET /Users.abl

Note: /Login.abl in web.xml is mapped to cart servlet (CartSvlt), not admin login.

File serving endpoints

  • GET /foto/*GetFileTnSvlt (thumbnail by default)
  • GET /fotoOriginali/*GetFileOrigSvlt (original file flow)

Multipart upload contract (common engine)

All race-image/file uploads go through AblServletSvlt.manageImgFileMultipartRequest + AcServlet.manageMultipartRequestParameters.

Key behavior:

  • File fields explicitly recognized: imgFile, nomeFile
  • UI also sends fileName for generic file upload; this still works (stored by original filename)
  • Temporary target directory: DOCBASE + tmp/ (getPathTmp())
  • Per-upload file size target: about 20000 KB for this servlet path

Upload race image

Endpoint:

  • POST /admin/pg/Gara.abl

Required form fields:

  • cmd=loadImg
  • imgFile (binary)
  • id (race id)
  • codImage (slot index)
  • totImgNumber (typically 3 in UI)

Storage details:

  • Race attachment path from Gara.getPathAttach() is _img/_gara/
  • Thumbnail is generated into _img/_gara/100/ (100x75)

Response schema (confirmed)

Response is JSON array with one object (JsonUploadImageResponse):

  • result (boolean)
  • message (string)
  • imgPath (string)

Example success payload shape:

[
  {
    "result": true,
    "message": "...Immagine 1 Salvata...",
    "imgPath": "../../_img/_gara/100/<generated-file>"
  }
]

Delete race image

Endpoint:

  • POST /admin/pg/Gara.abl

Fields:

  • cmd=removeImg
  • id
  • codImage
  • totImgNumber

Response schema is the same JsonUploadImageResponse[].

Upload CSV/file for race processing

Endpoint:

  • POST /admin/pg/Gara.abl

UI helper (Ab.saveFile) sends:

  • cmd=saveFile
  • fileName (binary file)
  • codFile (slot id, usually 1)
  • id (often 0 in UI flow)

Response schema (confirmed)

JSON array with one JsonUploadFileResponse object:

  • result (boolean)
  • message (string)
  • fileName (stored/original name)
  • fileNameLink (typically ../../tmp/<fileName>)

Example shape:

[
  {
    "result": true,
    "message": "...",
    "fileName": "punti-foto.csv",
    "fileNameLink": "../../tmp/punti-foto.csv"
  }
]

Race command API (/admin/pg/Gara.abl)

Confirmed custom commands in GaraSvlt:

  • asq + act=save (generic save used by admin UI toolbar)
  • ni (new record flow before save)
  • addPuntoFoto
  • delPuntoFoto
  • modPuntoFoto
  • indexFoto
  • noIndexFoto
  • creaPuntiFoto
  • indexCsvPisa
  • salvaFileCsv

Important parameters by command:

  • id_gara for race-level operations
  • id_puntoFoto and id_puntoFotoIdx for point selection
  • point fields such as descrizionePuntoFoto, pathRelativoFoto, tipoPuntoFoto

Race save payload fields (from admin/pg_RUS/gara.jsp + _V4/_js/_bean.js):

  • mandatory in practice: descrizione, dataGaraInizio, id_tipoGara
  • commonly sent: dataGaraFine, flgEventoInLinea, flgTipoIndex, pathBase, flgFree, localita
  • command envelope for save: cmd=asq, act=save

Confirmed fixed-flag value sets from UI templates:

  • flgEventoInLinea: 0 (Non In Linea), 1 (Stand By), 2 (In Linea)
  • flgTipoIndex: 0, 1
  • flgFree: 0 (No), 1 (SI)

Server-side normalization behavior:

  • Gara.save() appends trailing / to pathBase if missing.
  • if pathBase is empty and dataGaraInizio is set, server auto-derives pathBase as <year>/<id_gara>/.
  • PuntoFoto.prepareSave() appends trailing / to pathRelativoFoto if missing.

CSV flow coupling:

  1. cmd=saveFile uploads to tmp/ and returns fileName
  2. UI stores it into hidden field fileNameOnServer_1
  3. cmd=salvaFileCsv copies DOCBASE/tmp/<fileNameOnServer_1> to DOCBASE/admin/csv/<id_gara>.csv
  4. cmd=indexCsvPisa reads admin/csv/<id_gara>.csv via Gara.getImpCsvFileName() and updates matching photos

Processed photo transfer channel (/ReceiveFile.abl)

The original 3-piano -> WWW photo push does not use Gara.abl multipart for each processed photo. It uses UploadFile against a dedicated receiver servlet:

  • POST /ReceiveFile.abl
  • servlet class: com.ablia.servlet.ReceiveFileSvlt
  • typically unauthenticated (isSecureServlet=false in decompiled source)

Observed request shape:

  • query params: name, path, overwriteRemoteFile, bs
  • request body: raw file bytes stream

Usage in workflow:

  • destination path is computed per punto-foto on remote side (puntoFotoR.getPathCompletoFoto())
  • processed image and thumbnail (tn_<filename>) are both transferred
  • after transfer, photo flags are updated/indexed via DB-backed commands (indexFoto / CSV/indexing flows)

Image retrieval behavior

/foto/* (GetFileTnSvlt):

  • accepts id_foto query parameter, or extracts id from URL suffix pattern like name-<id>.jpg
  • if photo not found, serves _img/_imgNotFound.png
  • returns thumbnail by default in this servlet flow

/fotoOriginali/* (GetFileOrigSvlt):

  • routes to original-file logic
  • applies user/account checks (valid user, not expired, max photos)
  • blocks some originals by filename markers (_X, _Y, _Z) depending on profile
  • logs photo view events when original is served

Known response caveat

Do not treat result=true as universally reliable for success semantics:

  • in some error branches (_loadImg, _removeImg, _saveFile), code still returns result=true with an error message.

For robust clients, validate both:

  • result
  • message text + expected output field (imgPath / fileName non-empty)

Practical automation sequence

  1. Login on /admin/menu/Menu4.abl with cmdIU=check, store cookies.
  2. Create race on /admin/pg_RUS/Gara.abl with cmd=asq, act=save and race fields.
  3. Create and/or manage punti foto (addPuntoFoto, creaPuntiFoto, modPuntoFoto).
  4. Transfer processed files with /ReceiveFile.abl to remote race/punto paths.
  5. Trigger indexing (indexFoto per punto, or CSV via saveFile + salvaFileCsv + indexCsvPisa).
  6. Read thumbnails from /foto/* and originals from /fotoOriginali/*.