diff --git a/apps/keck/src/server/api/blocks/history.rs b/apps/keck/src/server/api/blocks/history.rs index a8b8a5c1..52c72d6d 100644 --- a/apps/keck/src/server/api/blocks/history.rs +++ b/apps/keck/src/server/api/blocks/history.rs @@ -21,18 +21,20 @@ pub struct BlockHistoryQuery { #[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct BlockHistory { pub workspace_id: String, - pub block_id: String, + pub field_name: Option, pub parent: Vec, pub content: String, + pub action: String, } impl From<(&str, &History)> for BlockHistory { fn from((workspace_id, history): (&str, &History)) -> Self { Self { workspace_id: workspace_id.into(), - block_id: history.id.clone(), + field_name: history.field_name.clone(), parent: history.parent.iter().map(|id| id.to_string()).collect::>(), content: history.content.clone(), + action: history.action.to_string(), } } } diff --git a/apps/keck/src/server/api/blocks/mod.rs b/apps/keck/src/server/api/blocks/mod.rs index be6f7378..643a7357 100644 --- a/apps/keck/src/server/api/blocks/mod.rs +++ b/apps/keck/src/server/api/blocks/mod.rs @@ -31,6 +31,7 @@ fn block_apis(router: Router) -> Router { fn workspace_apis(router: Router) -> Router { router .route("/block/:workspace/init", post(workspace::init_workspace)) + .route("/block/:workspace/export", get(workspace::export_workspace)) .route("/block/:workspace/client", get(clients::workspace_client)) .route("/block/:workspace/clients", get(clients::workspace_clients)) .route("/block/:workspace/history", get(history::history_workspace)) diff --git a/apps/keck/src/server/api/blocks/workspace.rs b/apps/keck/src/server/api/blocks/workspace.rs index 5fa39dad..e54722ea 100644 --- a/apps/keck/src/server/api/blocks/workspace.rs +++ b/apps/keck/src/server/api/blocks/workspace.rs @@ -102,6 +102,39 @@ pub async fn init_workspace( } } +/// Export a `Workspace` by id +/// - Return 200 Ok and `Workspace`'s data if export success. +/// - Return 404 Not Found if `Workspace` is not exists. +/// - Return 500 Internal Server Error if export failed. +#[utoipa::path( + get, + tag = "Workspace", + context_path = "/api/block", + path = "/{workspace}/export", + params( + ("workspace", description = "workspace id"), + ), + responses( + (status = 200, description = "Workspace export success", body = Vec), + (status = 404, description = "Workspace is not exists"), + (status = 500, description = "Failed to export a workspace") + ) +)] +pub async fn export_workspace(Extension(context): Extension>, Path(workspace): Path) -> Response { + info!("export_workspace: {}", workspace); + + match context.export_workspace(workspace).await { + Ok(data) => data.into_response(), + Err(e) => { + if matches!(e, JwstStorageError::WorkspaceNotFound(_)) { + return StatusCode::NOT_FOUND.into_response(); + } + warn!("failed to init workspace: {}", e.to_string()); + StatusCode::INTERNAL_SERVER_ERROR.into_response() + } + } +} + /// Create a `Workspace` by id /// - Return 200 Ok and `Workspace`'s data if init success or `Workspace` is /// exists. diff --git a/apps/keck/src/server/api/doc.rs b/apps/keck/src/server/api/doc.rs index e86d9308..102284ab 100644 --- a/apps/keck/src/server/api/doc.rs +++ b/apps/keck/src/server/api/doc.rs @@ -17,6 +17,7 @@ use super::{ subscribe::subscribe_workspace, subscribe::subscribe_test_hook, workspace::init_workspace, + workspace::export_workspace, workspace::get_workspace, workspace::set_workspace, workspace::delete_workspace, diff --git a/libs/jwst-codec/src/doc/history.rs b/libs/jwst-codec/src/doc/history.rs index 6d583db4..3f6faa27 100644 --- a/libs/jwst-codec/src/doc/history.rs +++ b/libs/jwst-codec/src/doc/history.rs @@ -147,6 +147,7 @@ impl StoreHistory { histories.push(History { id: item.id.to_string(), + field_name: item.parent_sub.clone(), parent: Self::parse_path(item, &parents), content: Value::from(&item.content).to_string(), action: HistoryAction::Update, @@ -163,6 +164,7 @@ impl StoreHistory { for item in deleted_items { histories.push(History { id: item.id.to_string(), + field_name: item.parent_sub.clone(), parent: Self::parse_path(&item, &parents), content: Value::from(&item.content).to_string(), action: HistoryAction::Delete, @@ -245,9 +247,20 @@ pub enum HistoryAction { Delete, } +impl ToString for HistoryAction { + fn to_string(&self) -> String { + match self { + Self::Insert => "insert".to_string(), + Self::Update => "update".to_string(), + Self::Delete => "delete".to_string(), + } + } +} + #[derive(Debug, PartialEq)] pub struct History { pub id: String, + pub field_name: Option, pub parent: Vec, pub content: String, pub action: HistoryAction,