use actix::Addr; use actix_web::{get, post, put, web, HttpResponse}; use emgauwa_lib::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbTag}; use emgauwa_lib::errors::{DatabaseError, EmgauwaError}; use emgauwa_lib::models::{convert_db_list, FromDbModel, Relay}; use emgauwa_lib::types::{ ControllerUid, ControllerWsAction, RequestRelayPulse, RequestRelayUpdate, }; use emgauwa_lib::utils; use sqlx::{Pool, Sqlite}; use crate::app_state; use crate::app_state::AppState; #[get("/relays")] pub async fn index(pool: web::Data<Pool<Sqlite>>) -> Result<HttpResponse, EmgauwaError> { let mut pool_conn = pool.acquire().await?; let db_relays = DbRelay::get_all(&mut pool_conn).await?; let relays: Vec<Relay> = convert_db_list(&mut pool_conn, db_relays)?; Ok(HttpResponse::Ok().json(relays)) } #[get("/relays/tag/{tag}")] pub async fn tagged( pool: web::Data<Pool<Sqlite>>, path: web::Path<(String,)>, ) -> Result<HttpResponse, EmgauwaError> { 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<Relay> = convert_db_list(&mut pool_conn, db_relays)?; Ok(HttpResponse::Ok().json(relays)) } #[get("/controllers/{controller_id}/relays")] pub async fn index_for_controller( pool: web::Data<Pool<Sqlite>>, path: web::Path<(String,)>, ) -> Result<HttpResponse, EmgauwaError> { let mut pool_conn = pool.acquire().await?; let (controller_uid,) = path.into_inner(); let uid = ControllerUid::try_from(controller_uid.as_str())?; 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<Relay> = convert_db_list(&mut pool_conn, db_relays)?; Ok(HttpResponse::Ok().json(relays)) } #[get("/controllers/{controller_id}/relays/{relay_num}")] pub async fn show_for_controller( pool: web::Data<Pool<Sqlite>>, path: web::Path<(String, i64)>, ) -> Result<HttpResponse, EmgauwaError> { let mut pool_conn = pool.acquire().await?; let (controller_uid, relay_num) = path.into_inner(); let uid = ControllerUid::try_from(controller_uid.as_str())?; 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("/controllers/{controller_id}/relays/{relay_num}")] pub async fn update_for_controller( pool: web::Data<Pool<Sqlite>>, app_state: web::Data<Addr<AppState>>, path: web::Path<(String, i64)>, data: web::Json<RequestRelayUpdate>, ) -> Result<HttpResponse, EmgauwaError> { let mut pool_conn = pool.acquire().await?; let (controller_uid, relay_num) = path.into_inner(); let uid = ControllerUid::try_from(controller_uid.as_str())?; let controller = DbController::get_by_uid(&mut pool_conn, &uid) .await? .ok_or(DatabaseError::NotFound)?; let mut relay = DbRelay::get_by_controller_and_num(&mut pool_conn, &controller, relay_num) .await? .ok_or(DatabaseError::NotFound)?; if let Some(name) = &data.name { relay = relay.update(&mut pool_conn, name.as_str()).await?; } if let Some(schedule_uids) = &data.schedules { if schedule_uids.len() == 7 { let mut schedules = Vec::new(); for s_uid in schedule_uids { schedules.push(s_uid.get_schedule(&mut pool_conn).await?); } DbJunctionRelaySchedule::set_schedules( &mut pool_conn, &relay, schedules.iter().collect(), ) .await?; } } if let Some(s_uid) = &data.active_schedule { let schedule = s_uid.get_schedule(&mut pool_conn).await?; DbJunctionRelaySchedule::set_schedule( &mut pool_conn, &relay, &schedule, utils::get_weekday(), ) .await?; } if let Some(tags) = &data.tags { relay.set_tags(&mut pool_conn, tags.as_slice()).await?; } let relay = relay.reload(&mut pool_conn).await?; let return_relay = Relay::from_db_model(&mut pool_conn, relay)?; app_state .send(app_state::Action { controller_uid: uid, action: ControllerWsAction::Relays(vec![return_relay.clone()]), }) .await??; Ok(HttpResponse::Ok().json(return_relay)) } #[post("/controllers/{controller_id}/relays/{relay_num}/pulse")] pub async fn pulse( pool: web::Data<Pool<Sqlite>>, app_state: web::Data<Addr<AppState>>, path: web::Path<(String, i64)>, data: web::Json<RequestRelayPulse>, ) -> Result<HttpResponse, EmgauwaError> { let mut pool_conn = pool.acquire().await?; let (controller_uid, relay_num) = path.into_inner(); let uid = ControllerUid::try_from(controller_uid.as_str())?; 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 duration = data.duration.filter(|&d| d > 0); app_state .send(app_state::Action { controller_uid: uid, action: ControllerWsAction::RelayPulse((relay.number, duration)), }) .await??; Ok(HttpResponse::Ok().finish()) // TODO add a message? }