193 lines
5.3 KiB
Rust
193 lines
5.3 KiB
Rust
use actix::Addr;
|
|
use actix_web::{delete, get, post, put, web, HttpResponse};
|
|
use emgauwa_common::db::{DbController, DbMacro};
|
|
use emgauwa_common::errors::{DatabaseError, EmgauwaError};
|
|
use emgauwa_common::models::{convert_db_list, FromDbModel, Macro, MacroAction, Relay};
|
|
use emgauwa_common::types::{
|
|
ControllerWsAction, EmgauwaUid, RequestMacroCreate, RequestMacroExecute, RequestMacroUpdate,
|
|
};
|
|
use sqlx::pool::PoolConnection;
|
|
use sqlx::{Pool, Sqlite};
|
|
|
|
use crate::app_state;
|
|
use crate::app_state::AppState;
|
|
use crate::handlers::EmgauwaMessage;
|
|
|
|
#[get("/macros")]
|
|
pub async fn index(pool: web::Data<Pool<Sqlite>>) -> Result<HttpResponse, EmgauwaError> {
|
|
let mut pool_conn = pool.acquire().await?;
|
|
|
|
let db_macros = DbMacro::get_all(&mut pool_conn).await?;
|
|
let macros: Vec<Macro> = convert_db_list(&mut pool_conn, db_macros)?;
|
|
|
|
Ok(HttpResponse::Ok().json(macros))
|
|
}
|
|
|
|
#[get("/macros/{macro_id}")]
|
|
pub async fn show(
|
|
pool: web::Data<Pool<Sqlite>>,
|
|
path: web::Path<(String,)>,
|
|
) -> Result<HttpResponse, EmgauwaError> {
|
|
let mut pool_conn = pool.acquire().await?;
|
|
|
|
let (macro_uid,) = path.into_inner();
|
|
let uid = EmgauwaUid::try_from(macro_uid.as_str())?;
|
|
|
|
let db_macro = DbMacro::get_by_uid(&mut pool_conn, &uid)
|
|
.await?
|
|
.ok_or(DatabaseError::NotFound)?;
|
|
|
|
let return_macro = Macro::from_db_model(&mut pool_conn, db_macro)?;
|
|
Ok(HttpResponse::Ok().json(return_macro))
|
|
}
|
|
|
|
#[post("/macros")]
|
|
pub async fn add(
|
|
pool: web::Data<Pool<Sqlite>>,
|
|
data: web::Json<RequestMacroCreate>,
|
|
) -> Result<HttpResponse, EmgauwaError> {
|
|
let mut pool_conn = pool.acquire().await?;
|
|
|
|
let new_macro = DbMacro::create(&mut pool_conn, EmgauwaUid::default(), &data.name).await?;
|
|
|
|
new_macro
|
|
.set_actions(&mut pool_conn, data.actions.as_slice())
|
|
.await?;
|
|
|
|
let return_macro = Macro::from_db_model(&mut pool_conn, new_macro)?;
|
|
Ok(HttpResponse::Created().json(return_macro))
|
|
}
|
|
|
|
#[put("/macros/{macro_id}")]
|
|
pub async fn update(
|
|
pool: web::Data<Pool<Sqlite>>,
|
|
path: web::Path<(String,)>,
|
|
data: web::Json<RequestMacroUpdate>,
|
|
) -> Result<HttpResponse, EmgauwaError> {
|
|
let mut pool_conn = pool.acquire().await?;
|
|
|
|
let (macro_uid,) = path.into_inner();
|
|
let uid = EmgauwaUid::try_from(macro_uid.as_str())?;
|
|
|
|
let db_macro = DbMacro::get_by_uid(&mut pool_conn, &uid)
|
|
.await?
|
|
.ok_or(DatabaseError::NotFound)?;
|
|
|
|
if let Some(name) = &data.name {
|
|
db_macro.update(&mut pool_conn, name).await?;
|
|
}
|
|
|
|
if let Some(actions) = &data.actions {
|
|
db_macro
|
|
.set_actions(&mut pool_conn, actions.as_slice())
|
|
.await?;
|
|
}
|
|
|
|
let return_macro = Macro::from_db_model(&mut pool_conn, db_macro)?;
|
|
Ok(HttpResponse::Ok().json(return_macro))
|
|
}
|
|
|
|
#[delete("/macros/{macro_id}")]
|
|
pub async fn delete(
|
|
pool: web::Data<Pool<Sqlite>>,
|
|
path: web::Path<(String,)>,
|
|
) -> Result<HttpResponse, EmgauwaError> {
|
|
let mut pool_conn = pool.acquire().await?;
|
|
|
|
let (macro_uid,) = path.into_inner();
|
|
let uid = EmgauwaUid::try_from(macro_uid.as_str())?;
|
|
|
|
DbMacro::delete_by_uid(&mut pool_conn, uid).await?;
|
|
Ok(HttpResponse::Ok().emgauwa_message("macro got deleted"))
|
|
}
|
|
|
|
#[put("/macros/{macro_id}/execute")]
|
|
pub async fn execute(
|
|
pool: web::Data<Pool<Sqlite>>,
|
|
app_state: web::Data<Addr<AppState>>,
|
|
path: web::Path<(String,)>,
|
|
query: web::Query<RequestMacroExecute>,
|
|
) -> Result<HttpResponse, EmgauwaError> {
|
|
let mut pool_conn = pool.acquire().await?;
|
|
|
|
let (macro_uid,) = path.into_inner();
|
|
let uid = EmgauwaUid::try_from(macro_uid.as_str())?;
|
|
|
|
let db_macro = DbMacro::get_by_uid(&mut pool_conn, &uid)
|
|
.await?
|
|
.ok_or(DatabaseError::NotFound)?;
|
|
|
|
let actions_db = match query.weekday {
|
|
None => db_macro.get_actions(&mut pool_conn).await?,
|
|
Some(weekday) => {
|
|
db_macro
|
|
.get_actions_weekday(&mut pool_conn, weekday)
|
|
.await?
|
|
}
|
|
};
|
|
let mut actions: Vec<MacroAction> = convert_db_list(&mut pool_conn, actions_db)?;
|
|
|
|
for action in &actions {
|
|
action.execute(&mut pool_conn).await?;
|
|
}
|
|
|
|
let affected_controllers = collect_affected_controllers(&mut pool_conn, &actions).await?;
|
|
|
|
for controller in affected_controllers {
|
|
let affected_relays =
|
|
collect_affected_relays(&mut pool_conn, &mut actions, &controller).await?;
|
|
|
|
app_state
|
|
.send(app_state::Action {
|
|
controller_uid: controller.uid,
|
|
action: ControllerWsAction::Relays(affected_relays.clone()),
|
|
})
|
|
.await??;
|
|
}
|
|
|
|
Ok(HttpResponse::Ok().emgauwa_message("macro got executed"))
|
|
}
|
|
|
|
async fn collect_affected_controllers(
|
|
pool_conn: &mut PoolConnection<Sqlite>,
|
|
actions: &Vec<MacroAction>,
|
|
) -> Result<Vec<DbController>, DatabaseError> {
|
|
let mut affected_controllers: Vec<DbController> = Vec::new();
|
|
for action in actions {
|
|
let controller_id = action.relay.r.controller_id;
|
|
|
|
if affected_controllers
|
|
.iter()
|
|
.any(|controller| controller.id == controller_id)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
let controller = DbController::get(pool_conn, controller_id)
|
|
.await?
|
|
.ok_or(DatabaseError::NotFound)?;
|
|
affected_controllers.push(controller);
|
|
}
|
|
Ok(affected_controllers)
|
|
}
|
|
|
|
async fn collect_affected_relays(
|
|
pool_conn: &mut PoolConnection<Sqlite>,
|
|
actions: &mut Vec<MacroAction>,
|
|
controller: &DbController,
|
|
) -> Result<Vec<Relay>, DatabaseError> {
|
|
let mut affected_relays: Vec<Relay> = Vec::new();
|
|
|
|
for action in actions {
|
|
if affected_relays
|
|
.iter()
|
|
.any(|relay| relay.r.id == action.relay.r.id)
|
|
|| action.relay.r.controller_id != controller.id
|
|
{
|
|
continue;
|
|
}
|
|
action.relay.reload(pool_conn)?;
|
|
affected_relays.push(action.relay.clone());
|
|
}
|
|
Ok(affected_relays)
|
|
}
|