You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Aggiungere login tramite Google e Facebook (OAuth)?
Chi sono gli utenti che utilizzano il servizio (privati e aziende con diversi privilegi)?
Notifiche per autorizzazione e scadenza del prestito (sempre se bisogna gestire restituzione dei prestiti)?
Punti principali di sviluppo
Priorità 1:
Registrazione/Login (OAuth e anche base con email/psw)
Logout
Inserimento prodotto che si vuole prestare
Pagina con lista di prodotti in prestito
Richiesta di prestito
Conferma di accettazione prestito
Priorità 2:
Elenco di prestiti attivi (sia prodotti dati che ricevuti)
Vista di storico prodotti inseriti
Vista di storico prestiti richiesti
Priorità 3:
Restituzione di prodotto prestato:
Apertura del locker per deposito prodotto a fine prestito
Apertura del locker per ritiro dell'prodotto a fine prestito
Modifica prodotto
Priorità 4:
Cambio password/password dimenticata
Sviluppi futuri:
Clustering di utenti (tramite IA)
Sistema di feedback degli utenti e prestiti
Pre-hash lato frontend delle password
Noleggio a pagamento
Passaggio a SQL più serio (tipo MySQL/MariaDB)
Notifiche push
Duplicazione dati dell'oggetto nei prestiti (per storico)
Parti principali del progetto
Le comunicazioni avvengono tramite chiamate/risposte HTTP (GET & POST) e i dati vengono passati in oggetti json
L'autenticazione avviene passando il token (ottenuto dal client in fase di login e signup) in un header chiamato Auth-Token (20 byte random generati dal server)
Se server va in un errore non recuperabile (es. eccezione), risponde al client con 500 (Internal Server Error)
Route per le api:
/api/{categoria-oggetto}/{id?}
Il metodo HTTP indica l'azione:
GET: ottieni elenco/singolo elemento (id opzionale)
POST: aggiungi nuovo oggetto (id non richiesto)
PUT: aggiorna oggetto (id richiesto)
DELETE: elimina oggetto (id richiesto)
categoria-oggetto può essere: user, product
id presente solo se si vuole accedere a, eliminare o modificare un elemento
A parte il login e la registrazione, tutte le richieste necessitano di un header chiamato token per l'autenticazione e identificazione dell'utente
Pagine del frontend
(corsivo: layout terminato, manca implementare chiamate ad API)
Priorità 1:
Login
Registrazione
Modifica dei locker dell'utente
Login con OAuth Google
Registrazione con OAuth Google
Pagina afterOAuthLogin per Google
Login con OAuth Facebook
Registrazione con OAuth Facebook
Pagina afterOAuthLogin per Facebook
Elenco tutti prodotti
Vista dettagli prodotto con tasto per richiesta prestito in locker specificato
Creazione prodotto
Modifica prodotto (con flag available)
Upload foto di prodotto
Pagina di info utente
Elenco di prestiti attivi (sia prodotti dati che ricevuti) con i vari tasti per confermare deposito e per prenotare locker di restituzione
Elenco propri prodotti
Priorità 2:
Vista di storico prodotti inseriti
Vista di storico prestiti richiesti
Priorità 3:
Pagina di termine prestito con conferma prodotto depositato
Priorità 4:
Pagina di modifica/recupero password
Esempio pagina dettagli prodotto
![[design files/Drawing 2022-11-17 22.42.10.excalidraw.png]]
Assunzioni
Implementazione della prenotazione e rilascio dei locker
In questo prototipo dell'applicazione viene assunto che il richiedente del prestito ritiri istantaneamente il prodotto nel momento in cui il proprietario lo deposita nel locker.
In particolare, nell'API /api/loan/start chiamata dal proprietario per confermare il deposito di un oggetto viene effettuata anche la chiamata all'API di release del locker.
La decisione è stata presa perché in un contesto reale dovrebbe essere il locker stesso a rilasciare la prenotazione nel momento in cui viene aperto dal richiedente.
Visualizzazione dei propri prodotti nella pagina principale
In questo prototipo dell'applicazione viene assunto che nella pagina principale l'utente possa vedere anche i propri prodotti inseriti
Tali prodotti non possono essere prenotati dall'utente stesso
In un contesto reale non andrebbero mostrati nella pagina principale ma solo nella pagina apposita ("I miei prodotti")
La decisione è stata presa per dimostrare il funzionamento dell'app in maniera più intuitiva e permettere di visualizzare i prodotti appena inseriti senza dover utilizzare un altro account
Nel codice abbiamo lasciato, commentato, il codice necessario a implementare questo filtro
Interazioni frontend <-> backend
Registrazione nuovo utente
Num
Client
Direzione
Server
Struttura dati
1
Invia dati utenti
->
POST /api/signup
email, password, name, surname, dateOfBirth (yyyy-mm-dd), province (intera), gender (M/F/*)
2
<-
Controlla se esiste già email registrata e se utente > 18 anni. Se tutto ok, risponde con 200 e token d'autenticazione, nome e id dell'utente
errorText (spiega in italiano errore a utente) OPPURE token, userId, name e surname
3
Se risposta è 400, mostra errorText. Altrimenti salva token e viene reindirizzato alla pagina di selezione dei locker
Selezione/modifica dei locker dell'utente
Num
Client
Direzione
Server
Struttura dati
1
Chiede la lista dei locker della provincia
->
GET /api/lockerList
2
<-
Torna l'elenco di locker della provincia dell'utente
lockerList (array di oggetti json con: id, nome, provincia, regione, address)
3
Mostra lista di locker all'utente. L'utente li seleziona e invia quelli selezionati
->
POST /api/saveUserLockers
lockers (array di id locker)
4
<-
Controlla se l'utente aveva almeno un locker selezionato. Se ce l'aveva ma adesso non ne ha selezionato neanche uno, torna 400 (Bad Request). Altrimenti salva in db i locker selezionati, risponde con 200
Login senza OAuth
Num
Client
Direzione
Server
Struttura dati
1
Invia email e password
->
POST api/signin
email, password
2
<-
Controlla in db se esiste account con email e password corrispondenti (nel db la password è hashata con salt) Risponde con 200 (credenziali valide) e rispondendo con un token e nome utente oppure 401 (credenziali non valide)
token, ownerId, name, surname
3
Si salva il token nel local storage che poi utilizzerà negli header per autenticarsi nelle successive risposte
->
Login con OAuth
GET /api/signinGoogle
GET /api/signinGoogle/callback/afterOAuthLogin?data={base64 del json}
oppure
GET /api/signinFacebook
GET /api/signinFacebook/callback
Num
Client
Direzione
Server
Struttura Dati
1
Comunica con autenticatore in base al tasto premuto (Google, Facebook...) fino ad ottenere i token necessari. Invia i token e il nome del servizio usato al server
->
dati di OAuth
2
<-
Controlla con autenticatore se token è valido. Se è valido, controlla in DB se esiste già mail registrata. Se l'utente esiste già ma non aveva creato account con OAuth vengono uniti i dati. Se non esiste crea account e manda dati utente. Se esiste utente ritorna token di utilizzo app
token, userId, name e surname (se esiste già utente), userData (se non esisteva utente, oggetto json con: name, surname, dateOfBirth (yyyy-mm-dd), gender (M/F/*))
3
Se non è presente token rimanda alla pagina di registrazione con dati utente precompilati. Se esiste salva il token nel local storage che poi utilizzerà negli header per autenticarsi nelle successive risposte
Lista di tutte le province italiane
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/provinces
2
<-
Legge le province dal file apposito e le rimanda all'utente
provinces (array di stringhe)
Visualizza info utente
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/user/{id}
2
<-
Legge l'utente dal db e lo rimanda al client
user (oggetto con id, name, surname, province, lockerList (array di locker di oggetti json con: id, name, province, region, address))
Se l'utente non ha neanche un locker selezionato, torna 403 (Forbidden). Salva i dati in db, comunica al client esito (200 se ok, 400 se mancano dati)
id (del prodotto appena creata)
3
Notifica utente dell'esito, se ok chiede se caricare foto (vedere flusso sotto). Infine mostra il nuovo prodotto
Creazione/modifica immagine prodotto
Num
Client
Direzione
Server
Struttura dati
1
->
POST /api/product/{id}/updateImage
image (Attenzione non è json ma multipart/form-data. L'immagine può avere come mimetype image/jpeg o image/png)
2
<-
Se l'utente non è il proprietario, torna 403 (Forbidden). Se è attivo un prestito con questo prodotto, torna 400. Altrimenti (comprime?) e salva foto come blob binario in db. Ritorna 200 oppure 500 se da errore
Se l'utente non è il proprietario, torna 403 (Forbidden). Se è attivo un prestito con questo prodotto (userBorrowProducts, di quel prodotto, con terminationDate = null), torna 403 (Forbidden). Altrimenti salva i dati in db, comunica al client esito (200 se ok, 400 se mancano dati)
3
Mostra il prodotto modificato
Visualizzazione singolo prodotto
Num
Client
Direzione
Server
Struttura dati
1
Chiede info
->
GET /api/product/{id}
2
<-
product (oggetto con id, user (oggetto con id, name, surname e province), title, description, maxLoanDays, insertionDate, lockerList (array di locker di oggetti json con: id, name, province, region, address))
3
Mostra i dati all'utente
Visualizzazione immagine prodotto
(L'URL di questa API non verrà utilizzata come ajax ma come src del tag <img> HTML)
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/product/{id}/image
2
<-
Legge da db il blob dell'immagine del prodotto e lo rimanda indietro come stream
(lo stream)
3
Visualizza l'immagine nel tag <img> HTML
Visualizzazione elenco prodotti
Num
Client
Direzione
Server
Struttura dati
1
Chiede elenco prodotti
->
GET /api/products
2
<-
Legge i prodotti dal db (dove availability = true e la provincia è la stessa del client) e li rimanda al client
products(array di oggetti composti da: id, user (oggetto con: id, nome e surname), title, description, maxLoanDays, insertionDate)
Prenotazione prodotto
Num
Client
Direzione
Server
Struttura dati
1
Invia i dati al server
->
POST /api/book
idProduct, lockerId
2
<-
Controlla che il prodotto abbia availability a true. Inoltre controlla che nella tabella userBorrowProducts non ci sia già un record di quel prodotto con terminationDate = null. Chiama le API di Sintra per prenotare il primo slot libero del locker (possibili errori: se non trova slot disponibili nel locker torna 409 (Conflict), se il prodotto non esiste torna 404 (Not Found), se il proprietario e il ricevente corrispondono torna 400 (Bad Request) e la spiegazione in errorText, se invece ci sono errori con la chiamata, torna 503 (Service Unavailable) e spiega l'errore in errorText). Imposta availability a false e salva avvio prestito nella tabella userBorrowProducts (impostando requestDate a oggi, lockerId con l'id del locker e lockerSlot con l'id dello slot del locker) (200), notifica utenti con email (a proprietario dà anche codice per aprire locker)
errorText se si è verificato un errore
3
Mostra conferma o errore all'utente
Conferma prodotto depositato (da proprietario)
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/loan/start/{idProduct}
2
<-
Aggiorna il campo loanStartDate della tabella userBorrowProducts, invia email di conferma agli utenti (al richiedente manda il secondo codice per aprire il locker), torna 200
Prenotazione locker per restituzione
Num
Client
Direzione
Server
Struttura dati
1
Invia i dati al server
->
GET /api/book/return/{idProduct}
2
<-
Controlla se il prodotto è effettivamente in un prestito attivo (è in userBorrowProduct con loanStartDate != null e terminationDate = null). Chiama le API di Sintra per prenotare il primo slot libero del locker (se non trova slot disponibili nel locker, torna 409 (Conflict)). In userBorrowProducts imposta returnLockerSlot (200), notifica utenti con email (al richiedente dà anche codice per aprire locker)
3
Mostra conferma o errore 409 all'utente
Termine prestito con conferma prodotto depositato
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/loan/close/{idProduct}
2
<-
Aggiorna il campo terminationDate della tabella userBorrowProducts, invia email di conferma agli utenti, torna 200
Elenco prestiti attivi (sia prodotti dati che ricevuti) e in attesa di conferma deposito
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/loans
2
<-
Legge la tabella userBorrowProducts le righe dove l'utente è proprietario oppure è il richiedente di un prestito e terminationDate è null. Calcola in base alla data corrente e al campo maxLoanDays dell'oggetto i giorni rimanenti alla fine del prestito. Calcola il flag myProduct, alreadyStarted e returnSlotBooked
loans (array di oggetti con: requestDate, loanStartDate, lockerSlot, returnLockerSlot, locker (con id, name, province, region, address), product (oggetto con id e title), owner (oggetto con id, name, surname), borrower (oggetto con id, name, surname), remainingDays, endDate, flag myProduct, flag alreadyStarted e flag returnSlotBooked
loans (array di oggetti con id, requestDate, loanStartDate, terminationDate, product (oggetto con: id, title), owner (oggetto con id, name, surname), borrower (oggetto con id, name, surname))
Storico prestiti richiesti
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/loans/requested
2
<-
loans (array di oggetti con id, requestDate, loanStartDate, terminationDate, product (oggetto con: id, title), owner (oggetto con id, name, surname), borrower (oggetto con id, name, surname))
Lista prodotti per proprietario
Num
Client
Direzione
Server
Struttura dati
1
->
GET /api/user/{id}/products
2
<-
Legge utente dal db e ritorna tutti gli oggetti da lui posseduti
products (array di oggetti con id, user (oggetto con id, name, surname e province), title, description, maxLoanDays, insertionDate, availability, lockerList (array di locker di oggetti json con: id, name, province, region, address))
3
Mostra i dati all'utente
Modifica/recupero password
Num
Client
Direzione
Server
Struttura dati
1
Preme il tasto "Richiedi nuova password"
->
GET /api/forgotPassword/{email}
2
<-
Se l'indirizzo email non esiste in DB, torna 404. Genera codice casuale a 12 cifre, lo salva in DB come nuova password in chiaro e lo invia per email all'utente e torna 200
3
Inserisce il codice ricevuto per email e una password nuova
->
POST /api/resetPassword
email, tempCode, newPassword
4
<-
Se l'indirizzo email o il codice temporaneo non sono validi, torna 403. Se sono validi imposta la nuova password (hashata) e genera un nuovo token, che salva in DB e torna all'utente