推进资源工具与本地优先兼容链收口

This commit is contained in:
lix-2026
2026-05-19 12:03:43 +08:00
parent 94be1c927b
commit 6fcdf78603
13 changed files with 1192 additions and 30 deletions
@@ -30,6 +30,7 @@ pub struct MediaBatchRequest {
#[serde(default)]
pub asset_ids: Vec<String>,
pub new_name: Option<String>,
pub target_document_id: Option<String>,
}
#[derive(Debug, Deserialize)]
@@ -510,10 +511,10 @@ pub async fn media_batch(
) -> Result<(StatusCode, HeaderMap, Json<Value>), WebError> {
let user_id = current_user_id(&state, &context).await;
let action = body.action.trim();
if action != "restore" && action != "delete" && action != "rename" {
if action != "restore" && action != "delete" && action != "rename" && action != "move" {
return Err(WebError::bad_request_code(
"media_batch_action_unsupported",
"Rust resource trash 当前仅支持附件 delete / restore / rename",
"Rust resource trash 当前仅支持附件 delete / restore / rename / move",
)
.with_context(&context)
.with_header(HEADER_MNOTE_WEB_OWNER, "mnote-web"));
@@ -553,6 +554,21 @@ pub async fn media_batch(
"newName": new_name,
}),
)
} else if action == "move" {
let target_document_id = require_id(
&context,
body.target_document_id.as_deref().unwrap_or_default(),
"targetDocumentId",
)?;
(
"tree.resource.move",
json!({
"resourceKind": "file",
"assetId": asset_id,
"fromDocumentId": document_id,
"targetDocumentId": target_document_id,
}),
)
} else {
(
"tree.resource.archive",
@@ -595,6 +611,29 @@ pub async fn media_batch(
)
.await?;
}
if action == "move" {
let target_document_id = require_id(
&context,
body.target_document_id.as_deref().unwrap_or_default(),
"targetDocumentId",
)?;
execute_convex_mutation_by_name(
state.config(),
&context,
"mediaAssets:patchById",
json!({
"userId": user_id,
"id": asset_id,
"patch": {
"document_id": target_document_id,
},
}),
workspace_id.as_deref(),
None,
"media_batch_move_patch",
)
.await?;
}
let command_result = execute_runtime_command_via_convex_with_artifacts(
&state,
&context,
@@ -602,12 +641,13 @@ pub async fn media_batch(
command,
)
.await;
if action == "rename" {
if action == "rename" || action == "move" {
if let Err(error) = command_result {
tracing::warn!(
error = %error.message(),
asset_id = %asset_id,
"tree.resource.rename artifact command 失败,已保留兼容 patch 结果"
action = %action,
"tree.resource artifact command 失败,已保留兼容 patch 结果"
);
}
} else {
@@ -624,10 +664,13 @@ pub async fn media_batch(
"restored": if action == "restore" { updated } else { 0 },
"deleted": if action == "delete" { updated } else { 0 },
"renamed": if action == "rename" { updated } else { 0 },
"moved": if action == "move" { updated } else { 0 },
"canonicalCommand": if action == "restore" {
"tree.resource.restore"
} else if action == "rename" {
"tree.resource.rename"
} else if action == "move" {
"tree.resource.move"
} else {
"tree.resource.archive"
},
@@ -1195,6 +1238,19 @@ mod tests {
assert_ne!(renamed["result"]["canonicalCommand"], "tree.node.rename");
}
#[tokio::test]
async fn resource_move_uses_resource_command_not_document_command() {
let moved = post_json(
"/api/media/batch",
json!({"action": "move", "assetIds": ["asset_1"], "targetDocumentId": "doc_2"}),
)
.await;
assert_eq!(moved["result"]["moved"], 1);
assert_eq!(moved["result"]["canonicalCommand"], "tree.resource.move");
assert_ne!(moved["result"]["canonicalCommand"], "documents.move");
}
#[tokio::test]
async fn mindmap_trash_routes_delete_restore_purge_and_empty() {
let deleted = delete_json("/api/mindmap/doc_1/mind_1").await;