From 948e191234bf38b8729fa670b3fb8807b904cd82 Mon Sep 17 00:00:00 2001 From: zzzz Date: Tue, 11 Jun 2024 00:08:13 +0200 Subject: [PATCH] refactored code to obey the frontend master's wishes (wip untested) --- migrations/0001_init.sql | 19 +++-- src/data.rs | 30 +++++++ src/main.rs | 144 +++++----------------------------- src/requests/get_requests.rs | 79 +++++++++++++++++++ src/requests/mod.rs | 2 + src/requests/post_requests.rs | 75 ++++++++++++++++++ 6 files changed, 219 insertions(+), 130 deletions(-) create mode 100644 src/data.rs create mode 100644 src/requests/get_requests.rs create mode 100644 src/requests/mod.rs create mode 100644 src/requests/post_requests.rs diff --git a/migrations/0001_init.sql b/migrations/0001_init.sql index 43c78e6..edeabf3 100644 --- a/migrations/0001_init.sql +++ b/migrations/0001_init.sql @@ -1,13 +1,20 @@ CREATE TABLE IF NOT EXISTS tea ( id serial PRIMARY KEY, - teaname VARCHAR(128) NOT NULL, - rfidcode VARCHAR(128) NOT NULL, - watertemp INT, - steepingseconds INT + tea_name VARCHAR(128) NOT NULL, + rfid_code VARCHAR(128) NOT NULL, + water_temp INT, + steeping_seconds INT NOT NULL, + registration_timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS steepinglog ( - tea_id INT, - steeping_seconds INT, + change_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + tea_id INT NOT NULL, + steeping_seconds INT NOT NULL, 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 ); \ No newline at end of file diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000..e827721 --- /dev/null +++ b/src/data.rs @@ -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, +} diff --git a/src/main.rs b/src/main.rs index f51b424..98a4676 100644 --- a/src/main.rs +++ b/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' use axum::{ - extract::{Path, State}, routing::{get, post}, - http::StatusCode, - response::IntoResponse, - Json, Router, + Router, }; -use serde::{Deserialize, Serialize}; -use sqlx::{FromRow, PgPool}; +use data::MyState; +use sqlx::PgPool; use tower_http::services::ServeFile; - -#[derive(Clone)] -struct MyState { - pool: PgPool, -} +mod data; +mod requests; +use crate::requests::{get_requests::*, post_requests::*}; #[shuttle_runtime::main] 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 router = Router::new() .nest_service("/", ServeFile::new("assets/index.html")) - .route("/addtea", post(add)) - .route("/deletetea", get(delete_by_id)) - .route("/updatetea", post(update)) - .route("/teabyid/:id", get(retrieve_by_id)) - .route("/teabyrfid/:rfid", get(retrieve_by_rfid)) - .route("/alltea", get(retrieve_all)) + // configuration + .route("/configuration", get(retrieve_config)) + .route("/configuration", post(update_config)) + // brewing events + //.route("/brewing-events", get(todo!())) + // 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); Ok(router.into()) } - -async fn retrieve_by_id( - Path(id): Path, - State(state): State, -) -> Result { - 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, - State(state): State, -) -> Result { - 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, -) -> Result { - 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, - Json(data): Json, -) -> Result { - 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, - Json(data): Json, -) -> Result { - 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, - State(state): State, -) -> Result { - 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, -} diff --git a/src/requests/get_requests.rs b/src/requests/get_requests.rs new file mode 100644 index 0000000..d7e025b --- /dev/null +++ b/src/requests/get_requests.rs @@ -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, +) -> Result { + 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, +) -> Result { + 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, + Path(id): Path, +) -> Result { + 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, + State(state): State, +) -> Result { + 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, + State(state): State, +) -> Result { + 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())), + } +} diff --git a/src/requests/mod.rs b/src/requests/mod.rs new file mode 100644 index 0000000..954291b --- /dev/null +++ b/src/requests/mod.rs @@ -0,0 +1,2 @@ +pub mod get_requests; +pub mod post_requests; diff --git a/src/requests/post_requests.rs b/src/requests/post_requests.rs new file mode 100644 index 0000000..ebf160e --- /dev/null +++ b/src/requests/post_requests.rs @@ -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, + Json(config): Json, +) -> Result { + 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, + Path(id): Path, + Json(data): Json, +) -> Result { + 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, + Json(data): Json, +) -> Result { + 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, + Json(tea_new): Json, +) -> Result { + 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())), + } +}