Welcome to Solidarity Purchansing Group, a project developed during the Software Engineering 2 course in Politecnico di Torino (academic year : 2021/2022).
- Mostafa Asadollahy
- Franscesco Ciarla
- Alessandra (Rhamiel) Comparetto
- Riccardo Di Dio
- Giacomo Inghilleri
- Antonio Materazzo
- Antonio Vespa
To develop this web app we used ReactJS (client side) and Express (server side).
The client side dependencies are:
- bootstrap, react-bootrap : for css styles and components
- dayjs : a library to manage dates
- react-calendar : a component needed to pick date and time
- react-qr-code : a component that allow the system to create a qr code
The server side dependencies are:
- bycrypt : used to hash the passwords of the users
- express-session, express-validator : used to manage user sessions (after the login)
- morgan : this module prints the route that has been called
- multer : used to upload images
- sqlite3 : needed to use the database
The database is implemented using SQlite3.
Frontend testing is performed using cypress and backend testing is performed with jest. We check the quality of our code relying on SonarCloud analysis.
- URL:
api/clients
- HTTP method: GET
- Description: get from the Client table all the clients present in the system.
- Request body: None
- Response body: an array with all the clients,
[
{
"userid": 0,
"name": "John",
"surname": "Doe",
"wallet": 50.30,
"address": "Corso Duca degli Abruzzi, 21, Torino"
},
{
"userid": 1,
"name": "Neil",
"surname": "Watts",
"wallet": 24.12,
"address": "Corso Como, 2, Milano"
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/client/<id>
- HTTP method: GET
- Description: get client given his id
- Request body: None
- Response body: a client
{
"userid": 0,
"name": "John",
"surname": "Doe",
"wallet": 50.30,
"address": "Corso Duca degli Abruzzi, 21, Torino"
}
- Response:
200 OK
,500 Internal Server Error
(generic error),404 Not Found
(not present or unavailable)
- URL:
api/client
- HTTP method: POST
- description: add a new client and user
- Request body:
{
"name": "Grrmafa",
"surname": "Idcamcv",
"username": "[email protected]",
"wallet": 50.30,
"address": "Corso Duca degli Abruzzi, 21, Torino",
"password": "123",
"type": "client"
}
- Response:
200 OK
,503 Internal Server Error
(generic error),422 Unprocessable Entity
(wrong parameters)
- URL:
api/orders?clientid=<id>
- HTTP method: GET
- Description: get client orders given his id
- Request body: None
- Response body: a list of orders
[
{
"id":2,
"userid":5,
"creationdate":"2021-11-12",
"claimdate":"2021-11-10 12:30",
"confirmationdate":"2021-11-09",
"deliveryaddress":"null",
"status":"completed"
},
{
"id":3,
"userid":5,
"creationdate":"2021-11-12",
"claimdate":"2021-11-10 12:30",
"confirmationdate":"2021-11-09",
"deliveryaddress":"null",
"status":"completed"
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/completeOrders?clientid=<id>
- HTTP method: GET
- Description: get client orders with products given his id
- Request body: None
- Response body: a list of orders with products
[
{
"id":1,
"userid": 4,
"creationdate": "2021-11-09",
"claimdate": "2021-11-10 12:30",
"confirmationdate": "2021-11-09",
"deliveryaddress": "null",
"deliveryid": "null",
"status": "confirmed",
"products":[
{
"productid": 1,
"productname": "Onion",
"quantity": 3,
"measure": "kg",
"price": 12.10
},
{
"productid": 2,
"productname": "Apple",
"quantity": 3,
"measure": "kg",
"price": 12.10
}
]
},
{
"id":2,
"userid": 4,
"creationdate": "2021-11-09",
"claimdate": "2021-11-10 12:30",
"confirmationdate": "2021-11-09",
"deliveryaddress": "null",
"deliveryid": "null",
"status": "confirmed",
"products":[
{
"productid": 1,
"productname": "Onion",
"quantity": 3,
"measure": "kg",
"price": 12.10
},
{
"productid": 2,
"productname": "Apple",
"quantity": 3,
"measure": "kg",
"price": 12.10
}
]
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/products/<date>
- HTTP method: GET
- Description: get from the table of all products which are available with a filtering query
- Request body: None
- Response body: an array with all available products given a date,
[
{
"id":46,
"name":"Garlic",
"description":"A description.",
"farmerid":2,
"price":12,
"measure":"kg",
"category":"Fruit and Vegetables",
"typeofproduction":"Biological agriculture",
"picture":"/img/garlic.png",
"dateavailability":"2021-11-21",
"quantity":12
},
{
"id":47,
"name":"Onion",
"description":"A description.",
"farmerid":2,
"price":12,
"measure":"kg",
"category":"Fruit and Vegetables",
"typeofproduction":"Biological agriculture",
"picture":"/img/onion.png",
"dateavailability":"2021-11-23",
"quantity":12
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/productsByFarmer/<farmerid>
- HTTP method: GET
- Description: get all products of a given farmer
- Request body: None
- Response body: an array of products,
[
{
"id":1,
"name": "Apple",
"description": "desc",
"farmerid": 2,
"measure": "kg",
"category": "Fruit",
"typeofproduction": "some type",
"picture": ""
},
{
"id":2,
"name": "Strawberry",
"description": "desc 2",
"farmerid": 2,
"measure": "kg",
"category": "Fruit",
"typeofproduction": "some type",
"picture": ""
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/product/
- HTTP method: PUT
- Request body:
[{
"id":2,
"name": "Strawberry",
"description": "desc 2",
"farmerid": 2,
"measure": "kg",
"category": "Fruit",
"typeofproduction": "some type",
"picture": ""
}]
- Description: updates a product
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/product/<productid>
- HTTP method: DELETE
- Request body: none
- Description: deletes a product given its id
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/orders/{orderid}
- HTTP method: PUT
- Request body:
[{
"status": "completed"
}]
- Description: update an order status given the order's id
- Request parameters: orderid
- Response:
200 OK
,503 Service Unavailable
(generic error),404 Not Found
(not present or unavailable)
- URL:
api/farmers
- HTTP method: GET
- Description: get for every farmer in the farmer table his place and his id
- Request body: None
- Response body:
[
{
"place":"Cooperativa di Dr. Jekyll",
"userid":1
},
{
"place":"Azienda Agricola di Mr. Hyde",
"userid":2
}
]
- Response:
500 Internal Server Error
(generic error), //TODO add 200 OK ?
Post the request to create an order by shop employee //TODO check if it corresponds with the actual implementation
- URL:
api/requests
- HTTP method: POST
- Description: creates an order with its orderlines and updates quantities
- Request body:
{
"userid":5,
"creationdate":"2021-11-12",
"claimdate":"2021-11-10 12:30",
"confirmationdate":"2021-11-09",
"deliveryaddress":"null",
"deliveryid": "null",
"status":"pending",
"products":
[
{
"productid": 1,
"name": "Apple",
"quantity": 2,
"measure": "kg",
"price": 12,
"total": "product.price * product.quantity"
},
{
"productid": 2,
"name": "Orange",
"quantity": 1,
"measure": "kg",
"price": 12,
"total": "product.price * product.quantity"
}
]
}
- Response:
200 OK
,503 Internal Server Error
(generic error),406 Unprocessable Entity
(some products not available)
- URL:
api/clients/{clientid}/?ammount={ammount}
- HTTP method: PUT
- Request body:
[{
"status": "completed"
}]
- Description: Top up the wallet of the given client adding the given ammount
- Request parameters: clientid, ammount
- Response:
200 OK
,503 Internal Server Error
(generic error),404 Not Found
(not present or unavailable)
- URL:
api/availability
- HTTP method: POST
- description: insert a new product availability
- Request body:
[{
"productid": 1,
"dateavailability": "2021-10-11",
"quantity": 6,
"status": "si",
"price": 15.00
}]
- Response:
200 OK
,503 Internal Server Error
(generic error)
- URL:
api/user
- HTTP method: POST
- description: add a new user to the system
- Request body:
[{
"username": "farmer1",
"password": "$2a$12$vOxMHcRpzCj9vLDUahqcsOJ9g.kqzCmUrc2DXy4Fxtk99kfuNQXqO",
"type": "farmer"
}]
- Response:
200 OK
,503 Internal Server Error
(generic error),404 Not Found
(not present or unavailable) (ACTUALLY it gives 422)
- URL:
api/orders/status/:status
- HTTP method: GET
- Description: get all the orders which have the given status
- Request body: None
- Response body: an array with all orders with the given status (empty array if there aren't any)
[
{
"id":2,
"userid":5,
"creationdate":"2021-11-12",
"claimdate":"2021-11-10 12:30",
"confirmationdate":"2021-11-09",
"deliveryaddress":"null",
"status":"completed"
},
{
"id":3,
"userid":5,
"creationdate":"2021-11-12",
"claimdate":"2021-11-10 12:30",
"confirmationdate":"2021-11-09",
"deliveryaddress":"null",
"status":"completed"
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/orders/farmers?farmerid=xxx&date=yyy&status=zzz
- HTTP method: GET
- Description: get the orderlines of the week related to a specific farmer and with a specific status (since the user can buy items from different farmers in a single order, the farmer who wants to know his ordered products should receive a list of orderlines from different orders)
- Request body: None
- Response body: an array of orderlines and product info
[
{
"orderid":1,
"productid":1,
"name":"Apple",
"quantity":3,
"measure":"kg",
"price":4
},
{
"orderid":2,
"productid":3,
"name":"Banana",
"quantity":1.5,
"measure":"kg",
"price":10
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/orderlines/
- HTTP method: PUT
- Request body:
[{
"orderid":1,
"productid":2,
"status": "packaged"
}]
- Description: update an orderline status given the related orderid and productid. Then it checks if this orderline update should affect the orderline's order status. If so, it updates it.
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/manager/weeklyReport/<date>
- HTTP method: GET
- Description: get a report about last week's unretrieved food
- Request body: None
- Response body: an array of products and quantities
[
{
"productid":1,
"name": "Apple",
"quantity": 3,
"measure": "kg",
"farmerName":"Neil",
"farmerSurname":"Watts"
},
{
"productid":2,
"name": "Banana",
"quantity": 1,
"measure": "kg",
"farmerName":"Eva",
"farmerSurname":"Rosalene"
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
api/manager/monthlyReport/<date>
- HTTP method: GET
- Description: get a report about last month's unretrieved food
- Request body: None
- Response body: an array of products and quantities
[
{
"productid":1,
"name": "Apple",
"quantity": 3,
"measure": "kg",
"farmerName":"Neil",
"farmerSurname":"Watts"
},
{
"productid":2,
"name": "Banana",
"quantity": 1,
"measure": "kg",
"farmerName":"Eva",
"farmerSurname":"Rosalene"
}
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
/api/clients/missedPickups/<clientid>
- HTTP method: PUT
- Request body:
{
"quantity": 1
}
- Description: increments by a given quantity the counter of missed pickups related to a client and return its actual value
- Request parameters: clientid
- Response body: the actual value of missed pickups
{
"missed_pickups": 1
}
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
/api/clients/missedPickups/<clientid>
- HTTP method: GET
- Request body: none
- Description: gets the counter of missed pickups related to a client
- Request parameters: clientid
- Response body: the actual value of missed pickups
{
"missed_pickups": 1
}
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
/api/suspended/<username>
- HTTP method: GET
- Request body: none
- Description: gets the date untill when the client is suspended
- Request parameters: username of the client
- Response body: the date untill the when the client is suspended, if it's not suspend it gets null.
{
"suspended": "2022-02-13"
}
- Response:
200 OK
,500 Internal Server Error
(generic error)
- URL:
/api/availability/<farmerid>?date=date
- HTTP method: GET
- Request body: none
- Description: gets the available products of a given farmer
- Request parameters: farmerid (params), date(query)
- Response body: Available products and their informations
[
{
"productid": 1,
"productName": "Artichoke",
"dateavailability": "2022-01-7 10:00",
"quantity": 6,
"measure": "kg",
"status": "pending",
"price": 15.00
},
{
"productid": 2,
"productName": "Apple",
"dateavailability": "2022-01-7 10:00",
"quantity": 6,
"measure": "kg",
"status": "pending",
"price": 15.00
},
]
- Response:
200 OK
,500 Internal Server Error
(generic error)
- POST
/api/login
- Request body: a credential object conatining username e password.
[{ "username": "farmer1", "password": "farmer1" }]
- Response body: the user object in the database.
[{ "id": 1, "username": "farmer1", "type": "farmer" }]
- Response:
200 OK
,401 Unothorized
(wrong username or password)
- DELETE
/logout
- Request body: empty.
- Response body: empty.
- Response:
200 OK
- GET
/api/sessions/current
- Request paameters: empty.
- Response body: the user object saved in the sessions current.
[{ "id": 1, "username": "farmer1", "name": "farmer" }]
- Response:
200 OK
,401 Unothorized
(wrong username or password)
- URL:
api/farmer
- HTTP method: POST
- Description: creates a new user and farmer
- Request body:
{
"username": "neilw",
"password": "qwerty",
"name": "Neil",
"surname": "Watts",
"place": "Cooperativa di Dr. Jekyll",
"address": "Via Trotta, 3, Torino, TO",
"type": "farmer"
}
- Response body: the farmer's id
- Response:
200 OK
,503 Internal Server Error
(generic error),422 Unprocessable Entity
- Route
/
: this route renders the Navbar, the Homepagea and the Modal that pops up to inform the logged client that his budget is insufficient. - Route
/products
: this route renders the page in which the shopemployee and the client can browse the producs, with their description and images. - Route
/farmerhome
: this route renders the farmer's homepage, in which he/she can report the availability of his/her products for next week. - Route
/editProduct
: this route renders the form that the farmer can use to edit product attributes - Route
/addProduct
: this route renders the form that the farmer can use to add a new product - Route
/employeehome
: this route renders the shopemployee homepage from which the employee can start any tasks he/she has to do - Route
/clienthome
:this route renders the client homepage from which he/she can perform any task desired - Route
/wallet/:id
: this route renders the form from which the shopemployee can top-up a client's wallet - Route
/productRequest
: renders the page from which the shopemployee can create and order on the behalf of the client. - Route
/manageOrders
: renders the page from which the shopemployee can check failed orders - Route
/handout
: renders the page used by the shopemployee to confirm the handout of an order - Route
/registerClient
: renders the page used by the shopemployee to add a new client in the system - Route
/login
: renders the page that lets farmer, shopemployees and clients to login - Route
/user
: renders the page giving the unregisterd user to choose the type of user he want to register as - Route
/user/:type
: renders the registration form to register as client, farmer or shopemploye, depending on the type choosen in the previews page. - Route
/user/client/password
: renders the page where a client previewsly inserted into the system by a shop epmloyee can change the password for hi account
- User (id, username, password, type)
- Farmer (userid, name, surname, place, address)
- Client(userid, name, surname, wallet, address, missed_pickups, suspended)
- Product (id, name, description, farmerid, price, measure, category, typeofproduction, picture)
- Availability (productid, dateavailability, quantity, status, price)
- Order (id, userid, creationdate, claimdate, confirmationdate, deliveryaddress, status)
- OrderLine (orderid, productid, quantity, price, status)
Type | Username | Password |
---|---|---|
Client | [email protected] | qwerty123 |
Client | [email protected] | qwerty123 |
Client | [email protected] | qwerty123 |
Client | [email protected] | qwerty123 |
Farmer | [email protected] | qwerty123 |
Farmer | [email protected] | qwerty123 |
Shop Employee | [email protected] | qwerty123 |
Manager | [email protected] | qwerty123 |
Warehouse manager | [email protected] | qwerty123 |
It's possible to get updates via telegram (you need to be a registered user) when the list of available products for the next week is posted by a farmer. In order to do so, you have to:
- open the following link: https://t.me/SPGP07bot
- type "/start"
- wait for updates