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 axum::extract::OriginalUri(uri): axum::extract::OriginalUri, 35 Json(input): Json<DeleteRecordInput>, 36) -> Response { 37 let (did, user_id, current_root_cid) = 38 match prepare_repo_write(&state, &headers, &input.repo, "POST", &uri.to_string()).await { 39 Ok(res) => res, 40 Err(err_res) => return err_res, 41 }; 42 if let Some(swap_commit) = &input.swap_commit 43 && Cid::from_str(swap_commit).ok() != Some(current_root_cid) { 44 return ( 45 StatusCode::CONFLICT, 46 Json(json!({"error": "InvalidSwap", "message": "Repo has been modified"})), 47 ) 48 .into_response(); 49 } 50 let tracking_store = TrackingBlockStore::new(state.block_store.clone()); 51 let commit_bytes = match tracking_store.get(&current_root_cid).await { 52 Ok(Some(b)) => b, 53 _ => { 54 return ( 55 StatusCode::INTERNAL_SERVER_ERROR, 56 Json(json!({"error": "InternalError", "message": "Commit block not found"})), 57 ) 58 .into_response(); 59 } 60 }; 61 let commit = match Commit::from_cbor(&commit_bytes) { 62 Ok(c) => c, 63 _ => { 64 return ( 65 StatusCode::INTERNAL_SERVER_ERROR, 66 Json(json!({"error": "InternalError", "message": "Failed to parse commit"})), 67 ) 68 .into_response(); 69 } 70 }; 71 let mst = Mst::load(Arc::new(tracking_store.clone()), commit.data, None); 72 let collection_nsid = match input.collection.parse::<Nsid>() { 73 Ok(n) => n, 74 Err(_) => { 75 return ( 76 StatusCode::BAD_REQUEST, 77 Json(json!({"error": "InvalidCollection"})), 78 ) 79 .into_response(); 80 } 81 }; 82 let key = format!("{}/{}", collection_nsid, input.rkey); 83 if let Some(swap_record_str) = &input.swap_record { 84 let expected_cid = Cid::from_str(swap_record_str).ok(); 85 let actual_cid = mst.get(&key).await.ok().flatten(); 86 if expected_cid != actual_cid { 87 return (StatusCode::CONFLICT, Json(json!({"error": "InvalidSwap", "message": "Record has been modified or does not exist"}))).into_response(); 88 } 89 } 90 let prev_record_cid = mst.get(&key).await.ok().flatten(); 91 if prev_record_cid.is_none() { 92 return (StatusCode::OK, Json(json!({}))).into_response(); 93 } 94 let new_mst = match mst.delete(&key).await { 95 Ok(m) => m, 96 Err(e) => { 97 error!("Failed to delete from MST: {:?}", e); 98 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": format!("Failed to delete from MST: {:?}", e)}))).into_response(); 99 } 100 }; 101 let new_mst_root = match new_mst.persist().await { 102 Ok(c) => c, 103 Err(e) => { 104 error!("Failed to persist MST: {:?}", e); 105 return ( 106 StatusCode::INTERNAL_SERVER_ERROR, 107 Json(json!({"error": "InternalError", "message": "Failed to persist MST"})), 108 ) 109 .into_response(); 110 } 111 }; 112 let op = RecordOp::Delete { 113 collection: input.collection, 114 rkey: input.rkey, 115 prev: prev_record_cid, 116 }; 117 let mut relevant_blocks = std::collections::BTreeMap::new(); 118 if new_mst.blocks_for_path(&key, &mut relevant_blocks).await.is_err() { 119 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to get new MST blocks for path"}))).into_response(); 120 } 121 if mst.blocks_for_path(&key, &mut relevant_blocks).await.is_err() { 122 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to get old MST blocks for path"}))).into_response(); 123 } 124 let mut written_cids = tracking_store.get_all_relevant_cids(); 125 for cid in relevant_blocks.keys() { 126 if !written_cids.contains(cid) { 127 written_cids.push(*cid); 128 } 129 } 130 let written_cids_str = written_cids 131 .iter() 132 .map(|c| c.to_string()) 133 .collect::<Vec<_>>(); 134 if let Err(e) = commit_and_log( 135 &state, 136 CommitParams { 137 did: &did, 138 user_id, 139 current_root_cid: Some(current_root_cid), 140 prev_data_cid: Some(commit.data), 141 new_mst_root, 142 ops: vec![op], 143 blocks_cids: &written_cids_str, 144 }, 145 ) 146 .await 147 { 148 return ( 149 StatusCode::INTERNAL_SERVER_ERROR, 150 Json(json!({"error": "InternalError", "message": e})), 151 ) 152 .into_response(); 153 }; 154 (StatusCode::OK, Json(json!({}))).into_response() 155}