diff --git a/emgauwa-core/src/handlers/v1/mod.rs b/emgauwa-core/src/handlers/v1/mod.rs index e221ca3..dca0eae 100644 --- a/emgauwa-core/src/handlers/v1/mod.rs +++ b/emgauwa-core/src/handlers/v1/mod.rs @@ -1,4 +1,5 @@ pub mod controllers; pub mod relays; pub mod schedules; +pub mod tags; pub mod ws; diff --git a/emgauwa-core/src/handlers/v1/relays.rs b/emgauwa-core/src/handlers/v1/relays.rs index 61b5141..5e03d59 100644 --- a/emgauwa-core/src/handlers/v1/relays.rs +++ b/emgauwa-core/src/handlers/v1/relays.rs @@ -1,6 +1,8 @@ -use actix_web::{get, web, HttpResponse}; -use emgauwa_lib::db::DbRelay; -use emgauwa_lib::models::{convert_db_list, Relay}; +use actix_web::{get, put, web, HttpResponse}; +use emgauwa_lib::db::errors::DatabaseError; +use emgauwa_lib::db::{DbController, DbRelay, DbTag}; +use emgauwa_lib::models::{convert_db_list, FromDbModel, Relay}; +use emgauwa_lib::types::ControllerUid; use serde::{Deserialize, Serialize}; use sqlx::{Pool, Sqlite}; @@ -22,3 +24,90 @@ pub async fn index(pool: web::Data>) -> Result>, + path: web::Path<(String,)>, +) -> Result { + let mut pool_conn = pool.acquire().await?; + + let (tag,) = path.into_inner(); + let tag_db = DbTag::get_by_tag(&mut pool_conn, &tag) + .await? + .ok_or(DatabaseError::NotFound)?; + + let db_relays = DbRelay::get_by_tag(&mut pool_conn, &tag_db).await?; + let relays: Vec = convert_db_list(&mut pool_conn, db_relays)?; + + Ok(HttpResponse::Ok().json(relays)) +} + +#[get("/api/v1/controllers/{controller_id}/relays")] +pub async fn index_for_controller( + pool: web::Data>, + path: web::Path<(String,)>, +) -> Result { + let mut pool_conn = pool.acquire().await?; + + let (controller_uid,) = path.into_inner(); + let uid = ControllerUid::try_from(controller_uid.as_str()).or(Err(ApiError::BadUid))?; + + let controller = DbController::get_by_uid(&mut pool_conn, &uid) + .await? + .ok_or(DatabaseError::NotFound)?; + + let db_relays = controller.get_relays(&mut pool_conn).await?; + + let relays: Vec = convert_db_list(&mut pool_conn, db_relays)?; + Ok(HttpResponse::Ok().json(relays)) +} + +#[get("/api/v1/controllers/{controller_id}/relays/{relay_num}")] +pub async fn show_for_controller( + pool: web::Data>, + path: web::Path<(String, i64)>, +) -> Result { + let mut pool_conn = pool.acquire().await?; + + let (controller_uid, relay_num) = path.into_inner(); + let uid = ControllerUid::try_from(controller_uid.as_str()).or(Err(ApiError::BadUid))?; + + let controller = DbController::get_by_uid(&mut pool_conn, &uid) + .await? + .ok_or(DatabaseError::NotFound)?; + + let relay = DbRelay::get_by_controller_and_num(&mut pool_conn, &controller, relay_num) + .await? + .ok_or(DatabaseError::NotFound)?; + + let return_relay = Relay::from_db_model(&mut pool_conn, relay)?; + Ok(HttpResponse::Ok().json(return_relay)) +} + +#[put("/api/v1/controllers/{controller_id}/relays/{relay_num}")] +pub async fn update_for_controller( + pool: web::Data>, + path: web::Path<(String, i64)>, + data: web::Json, +) -> Result { + let mut pool_conn = pool.acquire().await?; + + let (controller_uid, relay_num) = path.into_inner(); + let uid = ControllerUid::try_from(controller_uid.as_str()).or(Err(ApiError::BadUid))?; + + let controller = DbController::get_by_uid(&mut pool_conn, &uid) + .await? + .ok_or(DatabaseError::NotFound)?; + + let relay = DbRelay::get_by_controller_and_num(&mut pool_conn, &controller, relay_num) + .await? + .ok_or(DatabaseError::NotFound)?; + + let relay = relay.update(&mut pool_conn, data.name.as_str()).await?; + + relay.set_tags(&mut pool_conn, data.tags.as_slice()).await?; + + let return_relay = Relay::from_db_model(&mut pool_conn, relay)?; + Ok(HttpResponse::Ok().json(return_relay)) +} diff --git a/emgauwa-core/src/handlers/v1/schedules.rs b/emgauwa-core/src/handlers/v1/schedules.rs index b3d1710..81f908b 100644 --- a/emgauwa-core/src/handlers/v1/schedules.rs +++ b/emgauwa-core/src/handlers/v1/schedules.rs @@ -13,7 +13,6 @@ use crate::handlers::errors::ApiError; pub struct RequestSchedule { name: String, periods: DbPeriods, - #[serde(default)] // empty tags are allowed tags: Vec, } diff --git a/emgauwa-core/src/handlers/v1/tags.rs b/emgauwa-core/src/handlers/v1/tags.rs new file mode 100644 index 0000000..e5eb0e9 --- /dev/null +++ b/emgauwa-core/src/handlers/v1/tags.rs @@ -0,0 +1,16 @@ +use actix_web::{get, web, HttpResponse}; +use emgauwa_lib::db::DbTag; +use sqlx::{Pool, Sqlite}; + +use crate::handlers::errors::ApiError; + +#[get("/api/v1/tags")] +pub async fn index(pool: web::Data>) -> Result { + let mut pool_conn = pool.acquire().await?; + + let db_tags = DbTag::get_all(&mut pool_conn).await?; + + let tags: Vec = db_tags.iter().map(|t| t.tag.clone()).collect(); + + Ok(HttpResponse::Ok().json(tags)) +} diff --git a/emgauwa-core/src/handlers/v1/ws/controllers.rs b/emgauwa-core/src/handlers/v1/ws/controllers.rs index bf9933f..1ec5b12 100644 --- a/emgauwa-core/src/handlers/v1/ws/controllers.rs +++ b/emgauwa-core/src/handlers/v1/ws/controllers.rs @@ -106,9 +106,7 @@ impl ControllerWs { } } - /// helper method that sends ping to client every 5 seconds (HEARTBEAT_INTERVAL). - /// - /// also this method checks heartbeats from client + // helper method that sends ping to client every 5 seconds (HEARTBEAT_INTERVAL). fn hb(&self, ctx: &mut ws::WebsocketContext) { ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| { // check client heartbeats diff --git a/emgauwa-core/src/main.rs b/emgauwa-core/src/main.rs index d542f5c..fc4740c 100644 --- a/emgauwa-core/src/main.rs +++ b/emgauwa-core/src/main.rs @@ -61,6 +61,10 @@ async fn main() -> std::io::Result<()> { .service(handlers::v1::controllers::update) .service(handlers::v1::controllers::delete) .service(handlers::v1::relays::index) + .service(handlers::v1::relays::tagged) + .service(handlers::v1::relays::index_for_controller) + .service(handlers::v1::relays::show_for_controller) + .service(handlers::v1::relays::update_for_controller) .service(handlers::v1::schedules::index) .service(handlers::v1::schedules::tagged) .service(handlers::v1::schedules::show) @@ -68,6 +72,7 @@ async fn main() -> std::io::Result<()> { .service(handlers::v1::schedules::add_list) .service(handlers::v1::schedules::update) .service(handlers::v1::schedules::delete) + .service(handlers::v1::tags::index) .service(handlers::v1::ws::ws_controllers) }) .listen(listener)? diff --git a/emgauwa-lib/src/db/controllers.rs b/emgauwa-lib/src/db/controllers.rs index b154323..9b83768 100644 --- a/emgauwa-lib/src/db/controllers.rs +++ b/emgauwa-lib/src/db/controllers.rs @@ -79,6 +79,14 @@ impl DbController { conn: &mut PoolConnection, filter_uid: ControllerUid, ) -> Result<(), DatabaseError> { + if sqlx::query_scalar!("SELECT 1 FROM controllers WHERE uid = ?", filter_uid) + .fetch_optional(conn.deref_mut()) + .await? + .is_none() + { + return Err(DatabaseError::NotFound); + } + sqlx::query!("DELETE FROM controllers WHERE uid = ?", filter_uid) .execute(conn.deref_mut()) .await diff --git a/emgauwa-lib/src/db/relays.rs b/emgauwa-lib/src/db/relays.rs index 04456a7..a5033eb 100644 --- a/emgauwa-lib/src/db/relays.rs +++ b/emgauwa-lib/src/db/relays.rs @@ -108,18 +108,10 @@ impl DbRelay { &self, conn: &mut PoolConnection, new_name: &str, - new_number: i64, - new_controller: &DbController, ) -> Result { - sqlx::query!( - "UPDATE relays SET name = ?, number = ?, controller_id = ? WHERE id = ?", - new_name, - new_number, - new_controller.id, - self.id, - ) - .execute(conn.deref_mut()) - .await?; + sqlx::query!("UPDATE relays SET name = ? WHERE id = ?", new_name, self.id,) + .execute(conn.deref_mut()) + .await?; DbRelay::get(conn, self.id) .await? diff --git a/emgauwa-lib/src/db/schedules.rs b/emgauwa-lib/src/db/schedules.rs index 102df08..2e72061 100644 --- a/emgauwa-lib/src/db/schedules.rs +++ b/emgauwa-lib/src/db/schedules.rs @@ -77,6 +77,14 @@ impl DbSchedule { ScheduleUid::Any(_) => Ok(filter_uid), }?; + if sqlx::query_scalar!("SELECT 1 FROM schedules WHERE uid = ?", filter_uid) + .fetch_optional(conn.deref_mut()) + .await? + .is_none() + { + return Err(DatabaseError::NotFound); + } + sqlx::query!("DELETE FROM schedules WHERE uid = ?", filter_uid) .execute(conn.deref_mut()) .await diff --git a/emgauwa-lib/src/db/tag.rs b/emgauwa-lib/src/db/tag.rs index 3694e96..bd3e1cd 100644 --- a/emgauwa-lib/src/db/tag.rs +++ b/emgauwa-lib/src/db/tag.rs @@ -27,6 +27,13 @@ impl DbTag { .ok_or(DatabaseError::InsertGetError) } + pub async fn get_all(conn: &mut PoolConnection) -> Result, DatabaseError> { + sqlx::query_as!(DbTag, "SELECT * FROM tags") + .fetch_all(conn.deref_mut()) + .await + .map_err(DatabaseError::from) + } + pub async fn get( conn: &mut PoolConnection, id: i64,