feat: Controllo accessi RFID completo con gestione sessioni
- Aggiunto supporto multi-pattern RFID (US/IT layout) - Implementata invalidazione sessioni al restart del server - Schermata "badge non trovato" con countdown 30s - Notifica quando badge validatore passato senza utente - Database aggiornato con badge reali di test - Layout ottimizzato per tablet orizzontale - Banner NumLock per desktop - Toggle visibilità password - Carosello benvenuto multilingua (10 lingue) - Pagina debug RFID (/debug)
This commit is contained in:
@@ -13,7 +13,6 @@ Struttura modulare con separazione tra API, modelli e dati.
|
||||
backend-mock/
|
||||
├── main.py # Entry point con argparse
|
||||
├── Pipfile # Dipendenze pipenv
|
||||
├── requirements.txt # Backup dipendenze
|
||||
├── .gitignore
|
||||
├── api/
|
||||
│ ├── __init__.py
|
||||
@@ -22,7 +21,7 @@ backend-mock/
|
||||
│ ├── __init__.py
|
||||
│ └── models.py # Modelli Pydantic
|
||||
└── data/
|
||||
├── users_default.json # Dataset utenti default
|
||||
├── users_default.json # Dataset utenti default (badge reali)
|
||||
└── users_test.json # Dataset per test
|
||||
```
|
||||
|
||||
@@ -35,36 +34,40 @@ backend-mock/
|
||||
- [x] Creare cartella `backend-mock/`
|
||||
- [x] Creare `Pipfile` per pipenv
|
||||
- [x] Configurare `.gitignore` per Python
|
||||
- [ ] Creare struttura cartelle (`api/`, `schemas/`, `data/`)
|
||||
- [x] Creare struttura cartelle (`api/`, `schemas/`, `data/`)
|
||||
|
||||
### 2. Modelli Pydantic (`schemas/models.py`)
|
||||
|
||||
- [x] `LoginRequest` - badge + password
|
||||
- [x] `EntryRequest` - user_badge + validator_password
|
||||
- [x] `UserResponse` - dati utente + warning opzionale
|
||||
- [x] `RoomInfoResponse` - nome sala + meeting_id
|
||||
- [x] `RoomInfoResponse` - nome sala + meeting_id + **server_start_time**
|
||||
- [x] `LoginResponse` - success + message + token
|
||||
- [x] `EntryResponse` - success + message (SENZA welcome_message)
|
||||
- [ ] **DA FARE:** Spostare modelli in file dedicato
|
||||
- [x] Spostare modelli in file dedicato
|
||||
|
||||
### 3. Dati Mock (`data/*.json`)
|
||||
|
||||
- [x] Costanti validatore (badge `999999`, password `focolari`)
|
||||
- [x] Lista utenti mock (7 utenti con dati realistici)
|
||||
- [x] Mix di ruoli: Votante, Tecnico, Ospite
|
||||
- [x] Alcuni con `ammesso: false` per test
|
||||
- [x] URL foto placeholder (randomuser.me)
|
||||
- [ ] **DA FARE:** Estrarre dati in file JSON separato
|
||||
- [ ] **DA FARE:** Creare dataset alternativo per test
|
||||
- [ ] **DA FARE:** Caricare dati dinamicamente all'avvio
|
||||
- [x] Password validatore (solo password, badge gestito dal frontend)
|
||||
- [x] Lista utenti mock con **badge reali**:
|
||||
- `0008988288` - Marco Bianchi (Votante, ammesso)
|
||||
- `0007399575` - Laura Rossi (Votante, ammessa)
|
||||
- `0000514162` - Giuseppe Verdi (Tecnico, NON ammesso)
|
||||
- `0006478281` - **NON nel DB** (per test "non trovato")
|
||||
- [x] Estrarre dati in file JSON separato
|
||||
- [x] Creare dataset alternativo per test (`users_test.json`)
|
||||
- [x] Caricare dati dinamicamente all'avvio
|
||||
|
||||
**Nota:** I messaggi di benvenuto multilingua sono stati **RIMOSSI** dal backend.
|
||||
Il frontend gestirà autonomamente la visualizzazione internazionale con carosello.
|
||||
**Nota:** I messaggi di benvenuto multilingua sono gestiti dal frontend con carosello.
|
||||
|
||||
**TODO (da concordare con committenti):**
|
||||
|
||||
- Valutare se `login-validate` debba ricevere e verificare anche il badge del validatore
|
||||
|
||||
### 4. Routes API (`api/routes.py`)
|
||||
|
||||
- [x] `GET /info-room` - info sala
|
||||
- [x] `POST /login-validate` - autenticazione validatore
|
||||
- [x] `GET /info-room` - info sala + **server_start_time** per invalidare sessioni
|
||||
- [x] `POST /login-validate` - verifica solo password validatore
|
||||
- [x] `GET /anagrafica/{badge_code}` - ricerca utente
|
||||
- [x] Pulizia caratteri sentinel dal badge
|
||||
- [x] Confronto con e senza zeri iniziali
|
||||
@@ -73,27 +76,25 @@ Il frontend gestirà autonomamente la visualizzazione internazionale con carosel
|
||||
- [x] Verifica password validatore
|
||||
- [x] Verifica utente ammesso
|
||||
- [x] Risposta asettica (solo success + message)
|
||||
- [ ] **DA FARE:** Spostare routes in file dedicato
|
||||
- [x] Spostare routes in file dedicato
|
||||
|
||||
### 5. Entry Point (`main.py`)
|
||||
|
||||
- [x] Blocco `if __name__ == "__main__"`
|
||||
- [x] Configurazione uvicorn (host, port)
|
||||
- [x] Messaggi console all'avvio
|
||||
- [ ] **DA FARE:** Implementare argparse con opzioni:
|
||||
- `--port` / `-p` : porta server (default: 8000)
|
||||
- `--data` / `-d` : path file JSON dati (default: `data/users_default.json`)
|
||||
- `--host` : host binding (default: `0.0.0.0`)
|
||||
- [ ] **DA FARE:** Caricamento dinamico dati da JSON
|
||||
- [ ] **DA FARE:** Import routes da modulo `api`
|
||||
- [x] Implementare argparse con opzioni:
|
||||
- `--port` / `-p` : porta server (default: 8000)
|
||||
- `--data` / `-d` : path file JSON dati (default: `data/users_default.json`)
|
||||
- `--host` : host binding (default: `0.0.0.0`)
|
||||
- [x] Caricamento dinamico dati da JSON
|
||||
- [x] Import routes da modulo `api`
|
||||
|
||||
### 6. Struttura Base FastAPI
|
||||
### 6. Invalidazione Sessioni
|
||||
|
||||
- [x] Import FastAPI e dipendenze
|
||||
- [x] Configurazione app con titolo e descrizione
|
||||
- [x] Middleware CORS (allow all origins)
|
||||
- [x] Endpoint root `/` per health check
|
||||
- [ ] **DA FARE:** Refactor in struttura modulare
|
||||
- [x] `SERVER_START_TIME` generato all'avvio del server
|
||||
- [x] Restituito in `/info-room` per permettere al frontend di invalidare sessioni vecchie
|
||||
- [x] Se il server riparte, tutte le sessioni frontend vengono invalidate
|
||||
|
||||
---
|
||||
|
||||
@@ -101,19 +102,16 @@ Il frontend gestirà autonomamente la visualizzazione internazionale con carosel
|
||||
|
||||
```json
|
||||
{
|
||||
"validator": {
|
||||
"badge": "999999",
|
||||
"password": "focolari"
|
||||
},
|
||||
"validator_password": "focolari",
|
||||
"room": {
|
||||
"room_name": "Sala Assemblea",
|
||||
"meeting_id": "VOT-2024"
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"badge_code": "000001",
|
||||
"nome": "Maria",
|
||||
"cognome": "Rossi",
|
||||
"badge_code": "0008988288",
|
||||
"nome": "Marco",
|
||||
"cognome": "Bianchi",
|
||||
"url_foto": "https://...",
|
||||
"ruolo": "Votante",
|
||||
"ammesso": true
|
||||
@@ -126,25 +124,22 @@ Il frontend gestirà autonomamente la visualizzazione internazionale con carosel
|
||||
|
||||
## Comandi Esecuzione
|
||||
|
||||
### Avvio Standard
|
||||
### Via Script (consigliato)
|
||||
|
||||
```bash
|
||||
./dev.sh server # Avvia server con frontend
|
||||
./dev.sh server -p 9000 # Porta custom
|
||||
./dev.sh backend # Solo API, no frontend
|
||||
```
|
||||
|
||||
### Manuale
|
||||
|
||||
```bash
|
||||
cd backend-mock
|
||||
pipenv install
|
||||
pipenv run python main.py
|
||||
```
|
||||
|
||||
### Avvio con Parametri Custom
|
||||
```bash
|
||||
# Porta diversa
|
||||
pipenv run python main.py --port 9000
|
||||
|
||||
# Dataset test
|
||||
pipenv run python main.py --data data/users_test.json
|
||||
|
||||
# Combinato
|
||||
pipenv run python main.py -p 9000 -d data/users_test.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Rapidi
|
||||
@@ -153,29 +148,28 @@ pipenv run python main.py -p 9000 -d data/users_test.json
|
||||
# Health check
|
||||
curl http://localhost:8000/
|
||||
|
||||
# Info sala
|
||||
# Info sala (include server_start_time)
|
||||
curl http://localhost:8000/info-room
|
||||
|
||||
# Ricerca utente
|
||||
curl http://localhost:8000/anagrafica/000001
|
||||
# Ricerca utente reale
|
||||
curl http://localhost:8000/anagrafica/0008988288
|
||||
|
||||
# Badge non trovato
|
||||
curl http://localhost:8000/anagrafica/0006478281
|
||||
|
||||
# Login validatore
|
||||
curl -X POST http://localhost:8000/login-validate \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"badge": "999999", "password": "focolari"}'
|
||||
-d '{"badge": "qualsiasi", "password": "focolari"}'
|
||||
|
||||
# Richiesta ingresso (risposta asettica)
|
||||
# Richiesta ingresso
|
||||
curl -X POST http://localhost:8000/entry-request \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"user_badge": "000001", "validator_password": "focolari"}'
|
||||
-d '{"user_badge": "0008988288", "validator_password": "focolari"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Note Implementative
|
||||
## ✅ BACKEND COMPLETATO
|
||||
|
||||
- Gli endpoint puliscono automaticamente i caratteri `;`, `?`, `ò`, `_` dai badge
|
||||
- Il confronto badge avviene sia con che senza zeri iniziali
|
||||
- Le risposte seguono lo standard HTTP (200 OK, 401 Unauthorized, 404 Not Found, 403 Forbidden)
|
||||
- La documentazione OpenAPI è auto-generata su `/docs`
|
||||
- **Risposta `/entry-request`:** JSON asettico `{ success: true, message: "..." }` senza messaggi multilingua
|
||||
Tutti i task sono stati implementati e testati.
|
||||
|
||||
Reference in New Issue
Block a user