this repo has no description
1use crate::api::repo::record::utils::{commit_and_log, RecordOp}; 2use crate::api::repo::record::write::prepare_repo_write; 3use crate::repo::tracking::TrackingBlockStore; 4use crate::state::AppState; 5use axum::{ 6 extract::State, 7 http::{HeaderMap, StatusCode}, 8 response::{IntoResponse, Response}, 9 Json, 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#[derive(Deserialize)] 20pub struct DeleteRecordInput { 21 pub repo: String, 22 pub collection: String, 23 pub rkey: String, 24 #[serde(rename = "swapRecord")] 25 pub swap_record: Option<String>, 26 #[serde(rename = "swapCommit")] 27 pub swap_commit: Option<String>, 28} 29pub async fn delete_record( 30 State(state): State<AppState>, 31 headers: HeaderMap, 32 Json(input): Json<DeleteRecordInput>, 33) -> Response { 34 let (did, user_id, current_root_cid) = 35 match prepare_repo_write(&state, &headers, &input.repo).await { 36 Ok(res) => res, 37 Err(err_res) => return err_res, 38 }; 39 if let Some(swap_commit) = &input.swap_commit { 40 if Cid::from_str(swap_commit).ok() != Some(current_root_cid) { 41 return ( 42 StatusCode::CONFLICT, 43 Json(json!({"error": "InvalidSwap", "message": "Repo has been modified"})), 44 ) 45 .into_response(); 46 } 47 } 48 let tracking_store = TrackingBlockStore::new(state.block_store.clone()); 49 let commit_bytes = match tracking_store.get(&current_root_cid).await { 50 Ok(Some(b)) => b, 51 _ => return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Commit block not found"}))).into_response(), 52 }; 53 let commit = match Commit::from_cbor(&commit_bytes) { 54 Ok(c) => c, 55 _ => return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to parse commit"}))).into_response(), 56 }; 57 let mst = Mst::load( 58 Arc::new(tracking_store.clone()), 59 commit.data, 60 None, 61 ); 62 let collection_nsid = match input.collection.parse::<Nsid>() { 63 Ok(n) => n, 64 Err(_) => return (StatusCode::BAD_REQUEST, Json(json!({"error": "InvalidCollection"}))).into_response(), 65 }; 66 let key = format!("{}/{}", collection_nsid, input.rkey); 67 if let Some(swap_record_str) = &input.swap_record { 68 let expected_cid = Cid::from_str(swap_record_str).ok(); 69 let actual_cid = mst.get(&key).await.ok().flatten(); 70 if expected_cid != actual_cid { 71 return (StatusCode::CONFLICT, Json(json!({"error": "InvalidSwap", "message": "Record has been modified or does not exist"}))).into_response(); 72 } 73 } 74 let prev_record_cid = mst.get(&key).await.ok().flatten(); 75 if prev_record_cid.is_none() { 76 return (StatusCode::OK, Json(json!({}))).into_response(); 77 } 78 let new_mst = match mst.delete(&key).await { 79 Ok(m) => m, 80 Err(e) => { 81 error!("Failed to delete from MST: {:?}", e); 82 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": format!("Failed to delete from MST: {:?}", e)}))).into_response(); 83 } 84 }; 85 let new_mst_root = match new_mst.persist().await { 86 Ok(c) => c, 87 Err(e) => { 88 error!("Failed to persist MST: {:?}", e); 89 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to persist MST"}))).into_response(); 90 } 91 }; 92 let op = RecordOp::Delete { collection: input.collection, rkey: input.rkey, prev: prev_record_cid }; 93 let mut relevant_blocks = std::collections::BTreeMap::new(); 94 if let Err(_) = new_mst.blocks_for_path(&key, &mut relevant_blocks).await { 95 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to get new MST blocks for path"}))).into_response(); 96 } 97 if let Err(_) = mst.blocks_for_path(&key, &mut relevant_blocks).await { 98 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": "Failed to get old MST blocks for path"}))).into_response(); 99 } 100 let mut written_cids = tracking_store.get_all_relevant_cids(); 101 for cid in relevant_blocks.keys() { 102 if !written_cids.contains(cid) { 103 written_cids.push(*cid); 104 } 105 } 106 let written_cids_str = written_cids.iter().map(|c| c.to_string()).collect::<Vec<_>>(); 107 if let Err(e) = commit_and_log(&state, &did, user_id, Some(current_root_cid), Some(commit.data), new_mst_root, vec![op], &written_cids_str).await { 108 return (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": "InternalError", "message": e}))).into_response(); 109 }; 110 (StatusCode::OK, Json(json!({}))).into_response() 111}