this repo has no description
1use crate::api::repo::record::utils::{CommitParams, RecordOp, commit_and_log}; 2use crate::api::repo::record::write::prepare_repo_write; 3use crate::repo::tracking::TrackingBlockStore; 4use crate::state::AppState; 5use axum::{ 6 Json, 7 extract::State, 8 http::{HeaderMap, StatusCode}, 9 response::{IntoResponse, Response}, 10}; 11use cid::Cid; 12use jacquard::types::string::Nsid; 13use jacquard_repo::{commit::Commit, mst::Mst, storage::BlockStore}; 14use serde::Deserialize; 15use serde_json::json; 16use std::str::FromStr; 17use std::sync::Arc; 18use tracing::error; 19 20#[derive(Deserialize)] 21pub struct DeleteRecordInput { 22 pub repo: String, 23 pub collection: String, 24 pub rkey: String, 25 #[serde(rename = "swapRecord")] 26 pub swap_record: Option<String>, 27 #[serde(rename = "swapCommit")] 28 pub swap_commit: Option<String>, 29} 30 31pub async fn delete_record( 32 State(state): State<AppState>, 33 headers: HeaderMap, 34 Json(input): Json<DeleteRecordInput>, 35) -> Response { 36 let (did, user_id, current_root_cid) = 37 match prepare_repo_write(&state, &headers, &input.repo).await { 38 Ok(res) => res, 39 Err(err_res) => return err_res, 40 }; 41 if let Some(swap_commit) = &input.swap_commit 42 && Cid::from_str(swap_commit).ok() != Some(current_root_cid) { 43 return ( 44 StatusCode::CONFLICT, 45 Json(json!({"error": "InvalidSwap", "message": "Repo has been modified"})), 46 ) 47 .into_response(); 48 } 49 let tracking_store = TrackingBlockStore::new(state.block_store.clone()); 50 let commit_bytes = match tracking_store.get(&current_root_cid).await { 51 Ok(Some(b)) => b, 52 _ => { 53 return ( 54 StatusCode::INTERNAL_SERVER_ERROR, 55 Json(json!({"error": "InternalError", "message": "Commit block not found"})), 56 ) 57 .into_response(); 58 } 59 }; 60 let commit = match Commit::from_cbor(&commit_bytes) { 61 Ok(c) => c, 62 _ => { 63 return ( 64 StatusCode::INTERNAL_SERVER_ERROR, 65 Json(json!({"error": "InternalError", "message": "Failed to parse commit"})), 66 ) 67 .into_response(); 68 } 69 }; 70 let mst = Mst::load(Arc::new(tracking_store.clone()), commit.data, None); 71 let collection_nsid = match input.collection.parse::<Nsid>() { 72 Ok(n) => n, 73 Err(_) => { 74 return ( 75 StatusCode::BAD_REQUEST, 76 Json(json!({"error": "InvalidCollection"})), 77 ) 78 .into_response(); 79 } 80 }; 81 let key = format!("{}/{}", collection_nsid, input.rkey); 82 if let Some(swap_record_str) = &input.swap_record { 83 let expected_cid = Cid::from_str(swap_record_str).ok(); 84 let actual_cid = mst.get(&key).await.ok().flatten(); 85 if expected_cid != actual_cid { 86 return (StatusCode::CONFLICT, Json(json!({"error": "InvalidSwap", "message": "Record has been modified or does not exist"}))).into_response(); 87 } 88 } 89 let prev_record_cid = mst.get(&key).await.ok().flatten(); 90 if prev_record_cid.is_none() { 91 return (StatusCode::OK, Json(json!({}))).into_response(); 92 } 93 let new_mst = match mst.delete(&key).await { 94 Ok(m) => m, 95 Err(e) => { 96 error!("Failed to delete from MST: {:?}", e); 97 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": format!("Failed to delete from MST: {:?}", e)}))).into_response(); 98 } 99 }; 100 let new_mst_root = match new_mst.persist().await { 101 Ok(c) => c, 102 Err(e) => { 103 error!("Failed to persist MST: {:?}", e); 104 return ( 105 StatusCode::INTERNAL_SERVER_ERROR, 106 Json(json!({"error": "InternalError", "message": "Failed to persist MST"})), 107 ) 108 .into_response(); 109 } 110 }; 111 let op = RecordOp::Delete { 112 collection: input.collection, 113 rkey: input.rkey, 114 prev: prev_record_cid, 115 }; 116 let mut relevant_blocks = std::collections::BTreeMap::new(); 117 if new_mst.blocks_for_path(&key, &mut relevant_blocks).await.is_err() { 118 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to get new MST blocks for path"}))).into_response(); 119 } 120 if mst.blocks_for_path(&key, &mut relevant_blocks).await.is_err() { 121 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to get old MST blocks for path"}))).into_response(); 122 } 123 let mut written_cids = tracking_store.get_all_relevant_cids(); 124 for cid in relevant_blocks.keys() { 125 if !written_cids.contains(cid) { 126 written_cids.push(*cid); 127 } 128 } 129 let written_cids_str = written_cids 130 .iter() 131 .map(|c| c.to_string()) 132 .collect::<Vec<_>>(); 133 if let Err(e) = commit_and_log( 134 &state, 135 CommitParams { 136 did: &did, 137 user_id, 138 current_root_cid: Some(current_root_cid), 139 prev_data_cid: Some(commit.data), 140 new_mst_root, 141 ops: vec![op], 142 blocks_cids: &written_cids_str, 143 }, 144 ) 145 .await 146 { 147 return ( 148 StatusCode::INTERNAL_SERVER_ERROR, 149 Json(json!({"error": "InternalError", "message": e})), 150 ) 151 .into_response(); 152 }; 153 (StatusCode::OK, Json(json!({}))).into_response() 154}