2026-02-28 15:30:57 +01:00
|
|
|
# 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 login example (capture session cookie)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
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`).
|
|
|
|
|
|
|
|
|
|
## Public/web endpoints related to photos/users
|
|
|
|
|
|
|
|
|
|
- `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:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
"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:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
"result": true,
|
|
|
|
|
"message": "...",
|
|
|
|
|
"fileName": "punti-foto.csv",
|
|
|
|
|
"fileNameLink": "../../tmp/punti-foto.csv"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Race command API (`/admin/pg/Gara.abl`)
|
|
|
|
|
|
|
|
|
|
Confirmed custom commands in `GaraSvlt`:
|
2026-02-28 16:54:08 +01:00
|
|
|
- `asq` + `act=save` (generic save used by admin UI toolbar)
|
|
|
|
|
- `ni` (new record flow before save)
|
2026-02-28 15:30:57 +01:00
|
|
|
- `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`
|
|
|
|
|
|
2026-02-28 16:54:08 +01:00
|
|
|
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.
|
|
|
|
|
|
2026-02-28 15:30:57 +01:00
|
|
|
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
|
|
|
|
|
|
2026-02-28 16:54:08 +01:00
|
|
|
## 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)
|
|
|
|
|
|
2026-02-28 15:30:57 +01:00
|
|
|
## 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.
|
2026-02-28 16:54:08 +01:00
|
|
|
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`).
|
2026-02-28 15:30:57 +01:00
|
|
|
6. Read thumbnails from `/foto/*` and originals from `/fotoOriginali/*`.
|