mirror of
https://github.com/zzzzDev4/ias-tea-axum.git
synced 2025-04-21 07:41:21 +02:00
refactored code to obey the frontend master's wishes (wip untested)
This commit is contained in:
parent
76fe78bd48
commit
948e191234
6 changed files with 219 additions and 130 deletions
|
@ -1,13 +1,20 @@
|
||||||
CREATE TABLE IF NOT EXISTS tea (
|
CREATE TABLE IF NOT EXISTS tea (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
teaname VARCHAR(128) NOT NULL,
|
tea_name VARCHAR(128) NOT NULL,
|
||||||
rfidcode VARCHAR(128) NOT NULL,
|
rfid_code VARCHAR(128) NOT NULL,
|
||||||
watertemp INT,
|
water_temp INT,
|
||||||
steepingseconds INT
|
steeping_seconds INT NOT NULL,
|
||||||
|
registration_timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS steepinglog (
|
CREATE TABLE IF NOT EXISTS steepinglog (
|
||||||
tea_id INT,
|
change_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
steeping_seconds INT,
|
tea_id INT NOT NULL,
|
||||||
|
steeping_seconds INT NOT NULL,
|
||||||
steeping_tested_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
steeping_tested_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
|
default_steeping_time INT NOT NULL DEFAULT 120,
|
||||||
|
feedback_timeout BIGINT NOT NULL DEFAULT 60
|
||||||
);
|
);
|
30
src/data.rs
Normal file
30
src/data.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::{FromRow, PgPool};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MyState {
|
||||||
|
pub pool: PgPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct TeaNew {
|
||||||
|
pub tea_name: String,
|
||||||
|
pub rfid_code: String,
|
||||||
|
pub water_temp: i32,
|
||||||
|
pub steeping_seconds: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, FromRow)]
|
||||||
|
pub struct Tea {
|
||||||
|
pub id: i32,
|
||||||
|
pub tea_name: String,
|
||||||
|
pub rfid_code: String,
|
||||||
|
pub water_temp: i32,
|
||||||
|
pub steeping_seconds: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, FromRow)]
|
||||||
|
pub struct Config {
|
||||||
|
pub default_steeping_time: i32,
|
||||||
|
pub feedback_timeout: i32,
|
||||||
|
}
|
144
src/main.rs
144
src/main.rs
|
@ -1,21 +1,16 @@
|
||||||
// Invoke-WebRequest -Uri https://ias-tea-axum.shuttleapp.rs/addtea -Method POST -Body '{ "teaname": DemoTea, "rfidcode": "lo1rfId42", "watertemp": 200, "steepingseconds": 10}' -ContentType 'application/json'
|
// Invoke-WebRequest -Uri https://ias-tea-axum.shuttleapp.rs/addtea -Method POST -Body '{ "teaname": DemoTea, "rfidcode": "lo1rfId42", "watertemp": 200, "steepingseconds": 10}' -ContentType 'application/json'
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
http::StatusCode,
|
Router,
|
||||||
response::IntoResponse,
|
|
||||||
Json, Router,
|
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use data::MyState;
|
||||||
use sqlx::{FromRow, PgPool};
|
use sqlx::PgPool;
|
||||||
use tower_http::services::ServeFile;
|
use tower_http::services::ServeFile;
|
||||||
|
|
||||||
|
mod data;
|
||||||
#[derive(Clone)]
|
mod requests;
|
||||||
struct MyState {
|
use crate::requests::{get_requests::*, post_requests::*};
|
||||||
pool: PgPool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[shuttle_runtime::main]
|
#[shuttle_runtime::main]
|
||||||
async fn main(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_axum::ShuttleAxum {
|
async fn main(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_axum::ShuttleAxum {
|
||||||
|
@ -27,120 +22,21 @@ async fn main(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_axum::Shut
|
||||||
let state = MyState { pool };
|
let state = MyState { pool };
|
||||||
let router = Router::new()
|
let router = Router::new()
|
||||||
.nest_service("/", ServeFile::new("assets/index.html"))
|
.nest_service("/", ServeFile::new("assets/index.html"))
|
||||||
.route("/addtea", post(add))
|
// configuration
|
||||||
.route("/deletetea", get(delete_by_id))
|
.route("/configuration", get(retrieve_config))
|
||||||
.route("/updatetea", post(update))
|
.route("/configuration", post(update_config))
|
||||||
.route("/teabyid/:id", get(retrieve_by_id))
|
// brewing events
|
||||||
.route("/teabyrfid/:rfid", get(retrieve_by_rfid))
|
//.route("/brewing-events", get(todo!()))
|
||||||
.route("/alltea", get(retrieve_all))
|
// types of tea
|
||||||
|
.route("/types-of-tea", get(retrieve_types_of_tea))
|
||||||
|
.route("/types-of-tea/:id", post(update_tea_by_id))
|
||||||
|
.route("/types-of-tea/:id", get(retrieve_tea_by_id))
|
||||||
|
// teavail-device
|
||||||
|
.route("/add-tea", post(add_tea))
|
||||||
|
.route("/update-tea", post(update_tea_by_rfid)) // probably already covered by "update_tea_by_id"
|
||||||
|
.route("/delete-tea", get(delete_tea_by_id))
|
||||||
|
.route("/tea-by-rfid/:rfid", get(retrieve_tea_by_rfid))
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
|
|
||||||
Ok(router.into())
|
Ok(router.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn retrieve_by_id(
|
|
||||||
Path(id): Path<i32>,
|
|
||||||
State(state): State<MyState>,
|
|
||||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
|
||||||
match sqlx::query_as::<_, Tea>("SELECT * FROM tea WHERE id = $1")
|
|
||||||
.bind(id)
|
|
||||||
.fetch_one(&state.pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
|
||||||
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn retrieve_by_rfid(
|
|
||||||
Path(rfid): Path<String>,
|
|
||||||
State(state): State<MyState>,
|
|
||||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
|
||||||
match sqlx::query_as::<_, Tea>("SELECT * FROM tea WHERE rfidcode = $1 LIMIT 1")
|
|
||||||
.bind(rfid)
|
|
||||||
.fetch_optional(&state.pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
|
||||||
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn retrieve_all(
|
|
||||||
State(state): State<MyState>,
|
|
||||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
|
||||||
match sqlx::query_as::<_, Tea>("SELECT * FROM tea LIMIT 100")
|
|
||||||
.fetch_all(&state.pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(all_tea) => Ok((StatusCode::OK, Json(all_tea))),
|
|
||||||
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update(
|
|
||||||
State(state): State<MyState>,
|
|
||||||
Json(data): Json<TeaNew>,
|
|
||||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
|
||||||
match sqlx::query_as::<_, Tea>("UPDATE tea SET teaname = $1, watertemp = $2, steepingseconds = $3 WHERE rfidcode = $4 RETURNING id, teaname, rfidcode, watertemp, steepingseconds")
|
|
||||||
.bind(&data.teaname)
|
|
||||||
.bind(&data.watertemp)
|
|
||||||
.bind(&data.steepingseconds)
|
|
||||||
.bind(&data.rfidcode)
|
|
||||||
.fetch_one(&state.pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
|
||||||
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add(
|
|
||||||
State(state): State<MyState>,
|
|
||||||
Json(data): Json<TeaNew>,
|
|
||||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
|
||||||
println!("add");
|
|
||||||
match sqlx::query_as::<_, Tea>("INSERT INTO tea (teaname, rfidcode, watertemp, steepingseconds) VALUES ($1, $2, $3, $4) RETURNING id, teaname, rfidcode, watertemp, steepingseconds")
|
|
||||||
.bind(&data.teaname)
|
|
||||||
.bind(&data.rfidcode)
|
|
||||||
.bind(&data.watertemp)
|
|
||||||
.bind(&data.steepingseconds)
|
|
||||||
.fetch_one(&state.pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(tea) => Ok((StatusCode::CREATED, Json(tea))),
|
|
||||||
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn delete_by_id(
|
|
||||||
Path(id): Path<i32>,
|
|
||||||
State(state): State<MyState>,
|
|
||||||
) -> Result<impl IntoResponse, impl IntoResponse> {
|
|
||||||
match sqlx::query_as::<_, Tea>("DELETE FROM tea WHERE id = $1 RETURNING id, teaname, rfidcode, watertemp, steepingseconds")
|
|
||||||
.bind(id)
|
|
||||||
.fetch_one(&state.pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
|
||||||
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct TeaNew {
|
|
||||||
pub teaname: String,
|
|
||||||
pub rfidcode: String,
|
|
||||||
pub watertemp: i32,
|
|
||||||
pub steepingseconds: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, FromRow)]
|
|
||||||
struct Tea {
|
|
||||||
pub id: i32,
|
|
||||||
pub teaname: String,
|
|
||||||
pub rfidcode: String,
|
|
||||||
pub watertemp: i32,
|
|
||||||
pub steepingseconds: i32,
|
|
||||||
}
|
|
||||||
|
|
79
src/requests/get_requests.rs
Normal file
79
src/requests/get_requests.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
use axum::{
|
||||||
|
extract::{Path, State},
|
||||||
|
http::StatusCode,
|
||||||
|
response::IntoResponse,
|
||||||
|
Json,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::data::{MyState, Tea};
|
||||||
|
|
||||||
|
pub async fn retrieve_config(
|
||||||
|
State(state): State<MyState>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>("SELECT * FROM config")
|
||||||
|
.fetch_all(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(config) => Ok((StatusCode::OK, Json(config))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn retrieve_types_of_tea(
|
||||||
|
State(state): State<MyState>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>("SELECT * FROM tea LIMIT 400")
|
||||||
|
.fetch_all(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(all_tea) => Ok((StatusCode::OK, Json(all_tea))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn retrieve_tea_by_id(
|
||||||
|
State(state): State<MyState>,
|
||||||
|
Path(id): Path<i32>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>("SELECT * FROM tea WHERE id = $1 LIMIT 1")
|
||||||
|
.bind(id)
|
||||||
|
.fetch_optional(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used by teavail-device
|
||||||
|
pub async fn retrieve_tea_by_rfid(
|
||||||
|
Path(rfid): Path<String>,
|
||||||
|
State(state): State<MyState>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>("SELECT * FROM tea WHERE rfid_code = $1 LIMIT 1")
|
||||||
|
.bind(rfid)
|
||||||
|
.fetch_optional(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- currently not in use ---------------
|
||||||
|
|
||||||
|
pub async fn delete_tea_by_id(
|
||||||
|
Path(id): Path<i32>,
|
||||||
|
State(state): State<MyState>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>(
|
||||||
|
"DELETE FROM tea WHERE id = $1 RETURNING id, teaname, rfidcode, watertemp, steepingseconds",
|
||||||
|
)
|
||||||
|
.bind(id)
|
||||||
|
.fetch_one(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
2
src/requests/mod.rs
Normal file
2
src/requests/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod get_requests;
|
||||||
|
pub mod post_requests;
|
75
src/requests/post_requests.rs
Normal file
75
src/requests/post_requests.rs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
use crate::data::{MyState, Tea, TeaNew, Config};
|
||||||
|
use axum::{extract::{State, Path}, http::StatusCode, response::IntoResponse, Json};
|
||||||
|
|
||||||
|
pub async fn update_config(
|
||||||
|
State(state): State<MyState>,
|
||||||
|
Json(config): Json<Config>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>("UPDATE config SET default_steeping_time = $1, feedback_timeout = $2 RETURNING default_steeping_time, feedback_timeout")
|
||||||
|
.bind(&config.default_steeping_time)
|
||||||
|
.bind(&config.feedback_timeout)
|
||||||
|
.fetch_one(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(config) => Ok((StatusCode::OK, Json(config))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used by web-interface
|
||||||
|
pub async fn update_tea_by_id(
|
||||||
|
State(state): State<MyState>,
|
||||||
|
Path(id): Path<i32>,
|
||||||
|
Json(data): Json<TeaNew>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>("UPDATE tea SET tea_name = $1, water_temp = $2, steeping_seconds = $3 WHERE id = $4 RETURNING id, tea_name, rfid_code, water_temp, steeping_seconds")
|
||||||
|
.bind(&data.tea_name)
|
||||||
|
.bind(&data.water_temp)
|
||||||
|
.bind(&data.steeping_seconds)
|
||||||
|
.bind(id)
|
||||||
|
.fetch_one(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used by teavail-device
|
||||||
|
pub async fn update_tea_by_rfid(
|
||||||
|
State(state): State<MyState>,
|
||||||
|
Json(data): Json<TeaNew>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
match sqlx::query_as::<_, Tea>("UPDATE tea SET tea_name = $1, water_temp = $2, steeping_seconds = $3 WHERE rfid_code = $4 RETURNING id, tea_name, rfid_code, water_temp, steeping_seconds")
|
||||||
|
.bind(&data.tea_name)
|
||||||
|
.bind(&data.water_temp)
|
||||||
|
.bind(&data.steeping_seconds)
|
||||||
|
.bind(&data.rfid_code)
|
||||||
|
.fetch_one(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(tea) => Ok((StatusCode::OK, Json(tea))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn add_tea(
|
||||||
|
State(state): State<MyState>,
|
||||||
|
Json(tea_new): Json<TeaNew>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
|
println!("add");
|
||||||
|
match sqlx::query_as::<_, Tea>
|
||||||
|
(
|
||||||
|
"INSERT INTO tea (tea_name, rfid_code, water_temp, steeping_seconds) VALUES ($1, $2, $3, $4) RETURNING id, tea_name, rfid_code, water_temp, steeping_seconds"
|
||||||
|
)
|
||||||
|
.bind(&tea_new.tea_name)
|
||||||
|
.bind(&tea_new.rfid_code)
|
||||||
|
.bind(&tea_new.water_temp)
|
||||||
|
.bind(&tea_new.steeping_seconds)
|
||||||
|
.fetch_one(&state.pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(tea) => Ok((StatusCode::CREATED, Json(tea))),
|
||||||
|
Err(e) => Err((StatusCode::BAD_REQUEST, e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue