botserver/src/dashboards/handlers/widgets.rs

150 lines
5 KiB
Rust

use axum::{
extract::{Path, State},
Json,
};
use chrono::Utc;
use diesel::prelude::*;
use std::sync::Arc;
use uuid::Uuid;
use crate::core::shared::schema::dashboards::dashboard_widgets;
use crate::shared::state::AppState;
use crate::dashboards::error::DashboardsError;
use crate::dashboards::storage::{db_widget_to_widget, DbWidget};
use crate::dashboards::types::{AddWidgetRequest, UpdateWidgetRequest, Widget, WidgetData};
pub async fn handle_add_widget(
State(state): State<Arc<AppState>>,
Path(dashboard_id): Path<Uuid>,
Json(req): Json<AddWidgetRequest>,
) -> Result<Json<Widget>, DashboardsError> {
let pool = state.conn.clone();
let result = tokio::task::spawn_blocking(move || {
let mut conn = pool
.get()
.map_err(|e| DashboardsError::Database(e.to_string()))?;
let now = Utc::now();
let db_widget = DbWidget {
id: Uuid::new_v4(),
dashboard_id,
widget_type: req.widget_type.to_string(),
title: req.title,
position_x: req.position.x,
position_y: req.position.y,
width: req.position.width,
height: req.position.height,
config: serde_json::to_value(&req.config).unwrap_or_default(),
data_query: req.data_query.and_then(|q| serde_json::to_value(&q).ok()),
style: serde_json::to_value(&req.style.unwrap_or_default()).unwrap_or_default(),
created_at: now,
updated_at: now,
};
diesel::insert_into(dashboard_widgets::table)
.values(&db_widget)
.execute(&mut conn)
.map_err(|e: diesel::result::Error| DashboardsError::Database(e.to_string()))?;
Ok::<_, DashboardsError>(db_widget_to_widget(db_widget))
})
.await
.map_err(|e| DashboardsError::Internal(e.to_string()))??;
Ok(Json(result))
}
pub async fn handle_update_widget(
State(state): State<Arc<AppState>>,
Path((dashboard_id, widget_id)): Path<(Uuid, Uuid)>,
Json(req): Json<UpdateWidgetRequest>,
) -> Result<Json<Widget>, DashboardsError> {
let pool = state.conn.clone();
let result = tokio::task::spawn_blocking(move || {
let mut conn = pool
.get()
.map_err(|e| DashboardsError::Database(e.to_string()))?;
let mut db_widget: DbWidget = dashboard_widgets::table
.filter(dashboard_widgets::id.eq(widget_id))
.filter(dashboard_widgets::dashboard_id.eq(dashboard_id))
.first(&mut conn)
.map_err(|_| DashboardsError::NotFound("Widget not found".to_string()))?;
if let Some(title) = req.title {
db_widget.title = title;
}
if let Some(position) = req.position {
db_widget.position_x = position.x;
db_widget.position_y = position.y;
db_widget.width = position.width;
db_widget.height = position.height;
}
if let Some(config) = req.config {
db_widget.config = serde_json::to_value(&config).unwrap_or_default();
}
if let Some(data_query) = req.data_query {
db_widget.data_query = serde_json::to_value(&data_query).ok();
}
if let Some(style) = req.style {
db_widget.style = serde_json::to_value(&style).unwrap_or_default();
}
db_widget.updated_at = Utc::now();
diesel::update(dashboard_widgets::table.find(widget_id))
.set(&db_widget)
.execute(&mut conn)
.map_err(|e: diesel::result::Error| DashboardsError::Database(e.to_string()))?;
Ok::<_, DashboardsError>(db_widget_to_widget(db_widget))
})
.await
.map_err(|e| DashboardsError::Internal(e.to_string()))??;
Ok(Json(result))
}
pub async fn handle_delete_widget(
State(state): State<Arc<AppState>>,
Path((dashboard_id, widget_id)): Path<(Uuid, Uuid)>,
) -> Result<Json<serde_json::Value>, DashboardsError> {
let pool = state.conn.clone();
tokio::task::spawn_blocking(move || {
let mut conn = pool
.get()
.map_err(|e| DashboardsError::Database(e.to_string()))?;
let deleted = diesel::delete(
dashboard_widgets::table
.filter(dashboard_widgets::id.eq(widget_id))
.filter(dashboard_widgets::dashboard_id.eq(dashboard_id)),
)
.execute(&mut conn)
.map_err(|e: diesel::result::Error| DashboardsError::Database(e.to_string()))?;
if deleted == 0 {
return Err(DashboardsError::NotFound("Widget not found".to_string()));
}
Ok::<_, DashboardsError>(())
})
.await
.map_err(|e| DashboardsError::Internal(e.to_string()))??;
Ok(Json(serde_json::json!({ "success": true })))
}
pub async fn handle_get_widget_data(
State(_state): State<Arc<AppState>>,
Path((_dashboard_id, widget_id)): Path<(Uuid, Uuid)>,
) -> Result<Json<WidgetData>, DashboardsError> {
Ok(Json(WidgetData {
widget_id,
data: serde_json::json!([]),
fetched_at: Utc::now(),
}))
}